How can I update a element using SSJS in Xpages? - lotus-notes

I have a button, In Button on click event has set of codes,
I want to update two particular element using Server side Javascript.
But these are in different tags...
I want to update an element using SSJS code.
I am using Lotu notes 8.5.2.

Please check out this blog by Tim Tripcony, It will show you how to update two panels via partial refresh.
http://www.timtripcony.com/blog.nsf/d6plinks/TTRY-84B6VP
basically the code for two refreshes looks like below.
XSP.partialRefreshGet("#{id:div3}", {
onComplete: function() {
XSP.partialRefreshGet("#{id:div4}");
}
});

You should update the datasource for the components and dont try to 'refresh' them. If you realy want to update their values you use
getComponent(x).setValue();
Another approach would be to just use the partialrefreshget()..

Related

Auto-collapse any item in PrimeFaces PanelMenu on page loading

I'm writing a Primefaces 5.1 portlet.
It consists in a unique page containing a panelMenu, and I need that it starts with any panel collapsed everytime a user change page (on page loading).
But, if I open a panel, then change page, it will start showing that panel still opened.
I wasn't able to find any option to achieve this goal (e.g. collapsed=true, ignoreCookie=true or something similar).
The only solution I found was the following Javascript code:
PrimeFaces.widgets.myPanelMenu.collapseRootSubmenu(PrimeFaces.widgets.myPanelMenu.headers);
The problem is that this code will collapse any opened panel (so on page loading user is able to see panel menu collapsing animation) but it seems it doesn't store this state in its cookie/localstorage... the result is that on any page loading user can see this animation.
I'm sure it doesn't save its state, because the only way to "solve" the problem is to manually re-open and re-collapse the panels... then, on following page change, these menus start closed (and there is no animation).
I also tried to use PrimeFaces.widgets.sideMenuPanel.saveState() after collapsing, but with no success.
Do you have any idea about?
Thank you...
I found a solution to the problem.
If you read my discussion with Kukeltje (comments on my question), you will find that latest Primefaces' versions will solve the problem.
Otherwise, if you want to avoid upgrade or modify sources, and you need a quick fix based on Javascript only please read the following part of the answer.
It directly works on the component's state using JavaScript.
First of all you need to have a variable reference to your component:
<p:panelMenu model="#{menuBackingBean.menuModel}" widgetVar="sidePanelMenu" />
Then you should add the following JS code on document ready:
var panelMenu = PrimeFaces.widgets.sidePanelMenu;
// 1. On page loading collapses possible opened panels
panelMenu.collapseRootSubmenu(panelMenu.headers);
// following line is commented because it never should be necessary is not necessary (unless unexpected situation I never verified)
//clearSidePanelMenuPreferences();
// 2. Call the "clear preferences" actions on click on two tpe of links: first level are the panel link (used to open/close the menu) and second level are the destination links
// We need to fork also on the first level links to be sure it works after user clicks there then exit from the page in another way
panelMenu.headers.children("a").click(function(){setTimeout(clearSidePanelMenuPreferences, 500)}); // setTimeout is necessary because this event should be fired after preferences are written
panelMenu.headers.siblings().find("a").click(function(){clearSidePanelMenuPreferences();});
The function called to clear preferences are the following:
function clearSidePanelMenuPreferences() {
var panelMenu = PrimeFaces.widgets.sidePanelMenu;
panelMenu.expandedNodes = []; // clear the opened panels lists
panelMenu.saveState(); // store this information
}
Hope it helps
Please check this block of code
PF('myPanelMenu').headers.each(
function(){
var header = jQuery(this);
PF('myPanelMenu').collapseRootSubmenu(header);
header.removeClass('ui-state-hover');
}
);
I prefer to do this in order to execute this method only once and keep the menu option selected.
$(document).ready(function() {
if(location.pathname == "/cotizador/" || location.pathname == "/cotizador/faces/login.xhtml"){
var panelMenu = PrimeFaces.widgets.sidePanelMenu;
// 1. On page loading collapses possible opened panels
panelMenu.collapseRootSubmenu(panelMenu.headers);
panelMenu.expandedNodes = []; // clear the opened panels lists
panelMenu.saveState();
}
});

Opening different xpages forms from a view panel

I have an Xpages application that pulls data from another .nsf file. I have a view panel linked to a view in that db. The view has documents with several different forms in it. I want to be able to open each document in it's own form(xpage).
How do I write a computed At Runtime, open selected document using: statement that will select the correct Xpage to present the document.
If you use the Data View component instead of a View Panel, you can compute the pageName attribute, referencing the var attribute to return a different value for each row based on the document that row represents. The flexibility of the Data View component also makes it easier to make your app look more like a modern web application and less like an Excel spreadsheet. As an additional bonus, the mobile theme invokes a renderer that makes each Data View instance look like a native mobile list, so using Data Views instead of View Panels simplifies mobile development.
You have 2 options:
use "use xpage associated with form" and edit the form's property
use a SSJS formula to compute the Form. You provide a variable name in the view control var to access a view row as XSPViewEntry. If the Form is in a view column even one you don't display you use .getColumnValue otherwise getDocument.getItemValueString
Does that work for you?
Maybe this mothed can help you: Unable to get document page name for
Hope this helps
Mark
I had a similar problem today. I use only one form but 3 different xpages for associated with this form. I have 3 different document types in the view. I used rowData the get the type of the document.
try{
var v=rowData.getColumnValue("form");
if(v.indexOf("x")> -1){var page ="x.xsp"}
else if(v.indexOf("y") > -1){var page = "y.xsp"}
else{var page = "z.xsp"}
}catch(e){
var page = "x.xsp"
}
So to your view you can create a column with the value of the form and you can use it.
I have used the extension library Dynamic View control which has an event you can code to get a handle to the NotesViewEntry which was selected. See the demo database page Domino_DynamicView.xsp and the Custom Event Handler tab for an example.
Note, in 8.5.3 (I have not upgraded yet) if you add or edit the eventHandler for onColumnClick it will be added to the XPages source as an xe:eventHandler. It needs to be an xp:eventHandler to work. The way to do it is to copy the code in the source from the exiting event and delete it. Recreate the event and update the code. Then go back into the source and change the tags within the eventHandler to xp:.

#{javascript:viewScope.something} won't update after context.redirectToPage(...)

It is not long ago that I asked this question, which was about updating a property bundle after a csjs-induced full refresh. I solved it with a URL-parameter that lead to a context.redirectToPage.
Now I have an xPage with a jquery-based jqGrid, which receives a string with JSON-data from the viewScope and displays that data in a table. When I edit a record in the grid and hit 'submit' the grid posts a parameter called 'oper' with values like 'edit', 'add', etc., for which I check in the beforePageLoad event of the page and then execute the save method of my managed bean. After this I update the viewScope variable with the new JSON-string and conduct a full refresh in the above mentioned manner which had worked before.
<xp:this.beforePageLoad><![CDATA[#{javascript:
if (bccUser.isAdmin() && param.containsKey('oper') && param.get('oper').toString().length>0) {
bccGridDataHandler.saveGridDoc('RequestDummy','PersonRequestsDummy',param);
}
viewScope.put('jsonString',bccView.getViewColumnValue('PersonRequestsDummyJson',1));
print('jsonString in viewScope: '+viewScope.get('jsonString'));
if (bccUser.isAdmin() && param.containsKey('oper') && param.get('oper').toString().length>0) {
var url = context.getUrl().toSiteRelativeString(context);
if (url.indexOf('?')!=-1) {
url += "&doRefresh=true";
} else {
url += "?doRefresh=true";
}
print("redirecting to: "+url);
context.redirectToPage(url);
}}]]>
In the server console I can see the correct, updated JSON-string from the first print statement, so the save-method was successful and I have up-to-date data in my viewScope. The grid, however, does not show the updated data, neither does my test-div
<xp:text value="#{javascript:viewScope.get('jsonString')}" />
I also tried a partial refresh on the grid and div after updating the viewScope, but the same happened. After a manual refresh of the page everything is fine again. So, what's happening here? I just want to pass a simple string to a control. Am I mistaken again about the xPages-Lifecycle and the order of events?
Thanks in advance. Regards, Sarah
I think you are losing the viewScope value in the redirectToPage. Try with requestScope or sessionScope.
Thanks for all the suggestions, I tried them all out but unfortunately with no luck. The most interesting thing about this was, that when I put a clientside alert statement into the onClientLoad event it would just fire once, when I enter the page, but not after any of the context.redirect or .reload commands.
After all I solved the problem the following way:
I removed the redirect command from the beforePageLoad event and added the following parameter to the submit function of the jqGrid (see documentation here):
afterSubmit: function(response, postdata) {window.location.href=window.location.href;return [true,'',''];}
This works for me (onClientLoad is also triggered again after this), but still I wonder why a page refresh induced from the serverside doesn't do the same thing as a clientside refresh, or isn't able to imitate a clienside refresh.
I am not sure if the beforePageLoad event is the right one, have you considered generating the JSON in beforeRenderResponse?

XPages remove documents on server and trigger partial refresh

I am struggling with the following.
On my XPage I have a viewpanel component, but it is not bound to a notesview datasource, but to a hashmap stored in viewScope. Reasons for this is beyond scope of my question.
Since the lines in my view are not actually linked to the documents I cannot use the standard checkboxes and the related getSelectedDocIds. I do however want a way to remove the selected documents. I have a column with checkboxes containing the unid of the corresponding row.
So long story short. I have an array of unids and want to perform an action that does the following:
Display a dijit.Dialog asking for confirmation
If OK clicked call a function that does the following:
Remove the documents based on the unids
Refresh the viewpanel
I am thinking of the following 2 solutions, but in doubt what would be best (maybe a third, even simpler solution?)
Have the OK button of the dojo dialog call a function that does an XmlHttpRequest to an XAgent or plain old LS agent
Have the OK button trigger an eventhandler that runs on the server as described by JeremyHodge here. But how would I pass the unids as parameter and refresh the view afterwards?
Thanks!
Cant you just make use of the extension library dialog with the dialog button control. In this button control you can then
A third option would be to add a column to your datatable/view which contains checkboxes. On the onchange event of these boxes you add an eventhander which adds the value to a viewScope variable.
A button on the bottom (or top.) of the page you add the code you need to remove the selected items from the hashmap, delete the documents associate with the selected id's. this button can be a ordinary button with a partial refresh on the viewpanel. When you run into the bug that you cant use buttons in a dialog please use the extension library dialog control because this fixes that issue for you.
If the current user does not have the correct access level to delete documents you could use the sessionAsSigner global (assuming the signer of the design element has the correct access levels).
This way you dont need to go call an xAgent by xmlthttprequest and can stay with the default xpage methodology.
I hope this helps in some way
I would second #jjbsomhorst in the use of the extension library for the dialog box - if you use one at all. Usually users don't read dialog boxes. So the approach would be add the column with the checkboxes, but don't bother with an event handler, but bind them ALL with their value to ONE scopeVariable. On submission that variable will then hold an array with the selected UNID.
Then render a page that lists these documents and have a confirm button. While the new page affords a server round-trip the likelihood, that users actually pay attention is way higher. What you can do:
Have the normal page that renders the dialog with editable checkboxes and when the user clicks "Delete" you set something like viewScope.confirmDeleteMode=true; and use that as condition for the checkboxes and make them read-only AND set the class of the selected rows to "morituri" which in your CSS would have something like .morituri { color: white; background-color : red; font-weight: bold } and a new button "Confirm Delete" (and hide the Delete button).
This way you only have one page to deal with.
I went for option 2, which has the possibility to provide the partial refresh id. I passed the unids as a submitvalue like:
function doRemove(unids){
XSP.executeOnServer(ISP.UI.removeEventID, ISP.UI.removeRefreshID, {
params: {
'$$xspsubmitvalue': unids
},
onComplete : function() {
//alert('test')
}
});
}
The ISP.UI.removeEventID performs the following code:
var unids = context.getSubmittedValue();
removeDocuments(unids); //SSJS function performing the actual delete
viewScope.reload = 'reload' //triggers the hashmap to be rebuild based on new documentcollection

Automatically add rows to a Data View?

I am using a Data View control and the Pager Add Rows control to allow the user to add more rows to the data view.
Can I extend the Pager Add Rows control to automatically add rows to the Data View when the user reaches the bottom of screen?
Yes, you can do that easily with jquery. if you master dojo you can probably do it in similar ways. but this example show jQuery.
add jQuery to your xpage
add a new custom scriptlibrary to your xpage
put below code in your custom scriptlibrary
Add a addPageRows control to your xpages and connect it to a repeat.
All set, try it out.
$(function(){
$(window).scroll(function(){
if($(window).scrollTop() == $(document).height() - $(window).height()){
$("[id$='pagerAddRows1_ar'],[id$='pagerAddRows2_ar']").click();
}
});
})
The jquery code will try and find pagerAddRows1_ar or pagerAddRows2_ar and if found will click the link automatically when you reach the bottom of screen.
You can actually use this code with any kind of pager or link you have on your xpage. just make sure your code click the right id.

Resources