Extensions Library Dialog Box refresh / caching issue? - xpages

I seem to be having an issue with the extensions library dialog box either not refreshing or caching values.
Please see the very simplified example below. Basically the button pops up an extension library dialog box. Contained in the dialog box is a computed field with #Unique() as it's value. On our prod server the number is not being updated when the button is pressed. It works on the first button press but subsequent presses do not update the number.
This occurs only in production and a similar issue has only started occurring in the past couple of weeks. It still works fine on our Dev and QA servers.
My admin contacts are out right now so I don't know the differences in versions between the servers but I will post them when I learn that information.
Here is the code:
<xp:view xmlns:xp="http://www.ibm.com/xsp/core"
xmlns:xc="http://www.ibm.com/xsp/custom"
xmlns:xe="http://www.ibm.com/xsp/coreex">
<xp:this.resources>
<xp:script src="/Validation_SSJS.jss" clientSide="false"></xp:script>
</xp:this.resources>
<xp:br></xp:br>
<xp:br></xp:br>
<xe:dialog id="dlgMsg2" title="Message" style="width:400px;">
<xp:text escape="true" id="computedField1" value="#{javascript:return #Unique();}">
</xp:text>
</xe:dialog><xp:br></xp:br>
<xp:br></xp:br>
<xp:br></xp:br>
<xp:button value="Popup Message" id="button1">
<xp:eventHandler event="onclick" submit="true"
refreshMode="complete">
<xp:this.action><![CDATA[#{javascript:var dlg = getComponent("dlgMsg2");
dlg.show();}]]></xp:this.action>
</xp:eventHandler></xp:button>
</xp:view>
Update: The issue is occurring in both IE and Firefox so it does not appear to be browser related. I am guessing it is not Pistolstar related either as I had a previous issue with PS and Xpages. Pistolstar has discovered that issue and I will update my previous post when I get more details
Update: I checked and our QA and Prod servers are have version 8.5.3.20111208-0717 of the extension library.

I came up with a "workaround" to fix this issue. I added a refresh event handler for the onShow event of the dialog box.
<xe:dialog id="dlgMsg2" title="Message" style="width:400px;">
<xp:text escape="true" id="computedField1" value="#{javascript:return #Unique();}">
</xp:text>
<xp:eventHandler event="onShow" submit="true"
refreshMode="partial" refreshId="computedField1">
</xp:eventHandler></xe:dialog>
It would still be interesting to know the underlying issue.

In the All Properties section of the dialog there is a property called 'RefreshOnShow'.
When set to true the contents of the panel will be refreshed every time the panel goes from a hidden state to a visible state. This should resolve the issue that you are seeing.

It may be unlikely, but page persistence options in the xsp.properties could alter the way the page behaves across environments. There is the xsp.properties on the database and on the server. XPages Portable Command Guide has more details on the different settings, but settings could change what gets retained between requests.

Related

Loading Indicator Page Full Refresh in XPages

One of my XPages there are mo many design elements. The page takes time to load more than expected according to connection speed. I would like to create an indicator to show the logged user "The page is loading"... I made it for partial refresh and it works great but i couldn't make it for full refresh. I have been looking for a solution for this.
I can try jquery, dojo or ajax.
Any suggestion is important.
Regards
C.A.
I've not yet made a dedicated NotesIn9 show for it yet, but I do a demo of a technique in this TLCC webinar.
https://www.youtube.com/watch?v=jBaRSM9Ng_o&index=3&list=PL9nOJ-QrsuFa00dOsdE6EDh_l2fkiYD0D
The relevant part starts around the 26 minute part.
I'm doing this on loading the page initial but I'm sure could be adapted for a full refresh if you were already on the page.
The basic concept is on page load you don't actually load any long running data. You just sent the shell of the page and then in the onClientLoad event you trigger a partial refresh.
<xp:this.resources>
<xp:script src="/xpUtilities.jss" clientSide="false"></xp:script>
<xp:dojoModule name="extlib.dijit.ExtLib"></xp:dojoModule>
<xp:dojoModule name="extlib.dijit.Loading"></xp:dojoModule>
<xp:styleSheet href="/app.css"></xp:styleSheet>
</xp:this.resources>
Page 1
<xp:this.beforePageLoad><![CDATA[#{javascript:viewScope.put("vsHasData", false);}]]></xp:this.beforePageLoad>
  -  Header UI goes here....<xp:br></xp:br>
<xp:br></xp:br>
<xp:br></xp:br>
<xp:panel id="MainContentWrapper">
<xp:panel id="MainContent">
<xp:this.rendered><![CDATA[#{javascript:return viewScope.get("vsHasData");}]]></xp:this.rendered>
<xp:br></xp:br>
<xp:repeat id="repeat1" rows="100" var="rowData"
indexVar="rowIdx">
<xp:this.value><![CDATA[#{javascript:viewScope.get("vsStateMap").keySet()}]]></xp:this.value>
<xp:text escape="true" id="computedField2"
value="#{rowData}">
</xp:text>
-
<xp:text escape="true" id="computedField3">
<xp:this.value><![CDATA[#{javascript:viewScope.get("vsStateMap").get(rowData)}]]></xp:this.value>
<xp:this.converter>
<xp:convertNumber type="number"
integerOnly="true">
</xp:convertNumber>
</xp:this.converter>
</xp:text>
<xp:br></xp:br>
</xp:repeat>
<xp:br></xp:br>
<xp:br></xp:br>
</xp:panel>
</xp:panel>
<xp:eventHandler event="onClientLoad" submit="true" refreshMode="partial" refreshId="MainContentWrapper">
<xp:this.action><![CDATA[#{javascript:return getStateTotals();}]]></xp:this.action>
<xp:this.onStart><![CDATA[XSP.startAjaxLoading("Calculating State Totals. This may take a few moments.")]]></xp:this.onStart>
<xp:this.onComplete><![CDATA[XSP.endAjaxLoading()]]></xp:this.onComplete>
<xp:this.onError><![CDATA[XSP.endAjaxLoading()]]></xp:this.onError>
</xp:eventHandler>
That's a demo page. The stuff to look at is for dojo resources that are added, the fact that I start off hiding the "MainContent" vie a scoped variable and then the end onClientLoad bit.
So the page loads, but the data to generate the repeat control does NOT run because it's in a non rendered panel. So the users get to the page instantly. Then the onClientLoad kicks - on Start it shows a "Please Wait" kind of thing then runs the function to get the data.
When the data is completed, I set a scopedVariable to then show the mainContent area and the endAjaxLoading stuff then triggers and everything gets displayed.
How you do this will not be XPages-specific. It's important to understand the order of events.
User clicks link somewhere to open page
Browser sends request to server
Server receives request and loads component tree for page server-side
Server runs beforePageLoad, afterPageLoad, beforeRenderResponse events
Server generates HTML to send to the browser
Server runs afterRenderResponse event
Server passes resulting HTML to the screen
Browser receives response from server
So adding anything to the XPage that is the target of the browser request at step 2 cannot have an effect. You need to do something client-side at step 1, before the request is sent to the browser. If you think about how you did it for the partial refresh and what's happening, again it's running CSJS before triggering the partial refresh, the same process.
If users are coming externally, the only option is to send them to a redirect web page first, render that, and continue programmatically running step 1.

xe:dialog won't open in edit mode with view picklist OpenNTF control

I'm using the Extension Library and XPages to build a web based workflow application. One feature is to prompt a dialog and select the next approver before submitting it forward.
For new documents, the dialog appears, and it also appears when in read mode. It never opens for a saved document. I need it to work in SSJS, though the dialog does open in CSJS. Here is some of the code:
xpMain.xsp contains two custom controls: ccButtons and ccWFloDialogs.
ccButtons "Submit" button:
getComponent('dlgNextOwner').show();
ccWFloDialogs "dlgNextOwner" dialog:
<xe:dialog id="dlgNextOwner" title="Select Supervisor">
<xe:formTable id="ftDlgNextOwner" formTitle="Select Supervisor"
formDescription="You may select a different supervisor."
disableErrorSummary="true">
<xp:this.facets>
<xe:formRow id="formRow1" xp:key="footer" for="txtWFloNextOwner"
labelWidth="125px">
<xp:inputText id="txtWFloNextOwner" style="width:200px"
value="#{viewScope.nextOwner}">
</xp:inputText>
<xe:namePicker id="npNextOwner" dialogTitle="Select Supervisor"
for="txtWFloNextOwner">
<xe:this.dataProvider>
<xe:dominoNABNamePicker addressBookSel="all-public"></xe:dominoNABNamePicker>
</xe:this.dataProvider>
</xe:namePicker>
</xe:formRow>
</xp:this.facets>
</xe:formTable>
</xe:dialog>
In CSJS, I can use the following code and it successfully opens the dialog:
XSP.openDialog("#{id:dlgNextOwner}");
I'm also using Mark Hughes' picklist from the extension library, and if I remove the panel which contains the control and data source, the dialog shows up in SSJS! The code is in a custom control, although, if it's directly in the XPage, the problem is the same. Here is the code for the panel:
<xp:panel
id="vendorDiv">
<xp:this.data>
<xp:dominoView
var="nvVend"
viewName="V_Vend"
ignoreRequestParams="true"
databaseName="other/lookupdb.nsf"
startKeys="#{javascript:viewScope.srchVend}">
</xp:dominoView>
</xp:this.data>
<xe:formTable
id="ftGetVendor"
disableErrorSummary="true"
labelPosition="above">
<xe:formRow
id="frVendor"
for="cfVendorName"
label="Name of the Vendor:">
<xp:text
escape="true"
id="cfVendorName"
value="#{currentDocument.VendorName}"
style="width:200px">
</xp:text>
<xc:viewpicklist
rowsPerPage="15"
buttonImage="./add.png"
tableClass="tablecellgreen"
headerClass="headerclass"
rowClass="odd, even"
searchBar="false"
searchButtonText="Search"
searchButtonClass="button2"
searchBarClass="headerclass"
pagerStyleFirst="navbutton1"
pagerStylePrevious="navbutton2"
pagerStyleCurrent="navbutton4"
pagerStyleNext="navbutton2"
pagerStyleLast="navbutton3"
typeAheadBar="true"
select="Column"
onReturn="Set Scope Value"
bottomBarClass="bottomround headerclass"
cancelButtonText="Cancel"
cancelButtonClass="button2 floatthisright"
type="Single Value"
finishButtonText="Finish"
finishButtonClass="button2 floatthisright"
multiSelectButtonAddImg="./add.png"
multiSelectButtonRemoveImg="./delete.png"
picklistButtonClass="button"
openDialogWith="Link"
picklistLinkImg="./add.png"
multiSelectLinkAddImg="./add.png"
multiSelectLinkRemoveImg="./delete.png"
selectWith="Link"
clearSearchImg="./cross.png"
SelectCellWidth="30px"
dialogID="dlgVend"
dialogTitle="Select a Vendor"
dialogWidth="80%"
refreshID="vendorDiv"
ssjsSelectFunction="getVendorInfo"
varName="viewScope.vendorInfo"
datasrc="nvVend"
selectColumn="4"
linkImg="./add.png"
typeAheadVar="viewScope.srchVend">
<xc:this.viewColumn>
<xp:value>0</xp:value>
<xp:value>1</xp:value>
<xp:value>2</xp:value>
<xp:value>3</xp:value>
</xc:this.viewColumn>
</xc:viewpicklist>
</xe:formRow>
<xe:formRow
id="frVendorStatus"
for="cfVendorStatus"
label="Vendor Registration Status:">
<xp:text
escape="true"
id="cfVendorStatus"
value="#{currentDocument.VendorStatus}">
</xp:text>
</xe:formRow>
<xe:formRow
id="frVendorCountry"
for="cfVendorCountry"
label="Country Name:">
<xp:text
escape="true"
id="cfVendorCountry"
value="#{currentDocument.VendorCountry}">
</xp:text>
</xe:formRow>
</xe:formTable>
</xp:panel>
The requested vendor information populates the fields, without any problem or errors. However, something here seems to prevent dialogs from opening up using SSJS.
Can anyone see anything obvious I'm missing? The data source is in the panel, ignoreRequestParams is true (otherwise it doesn't work).
The main data source is in the entire XPage context. I tried to add the ccWFloDialog custom control outside the main panel, and change the data source to the panel, but that didn't work.
Any ideas?
Forget the dialog for now. This is probably data source related. Suggest you get it working just on the xpage first. With visible fields. then maybe use the rendered property to get it working on the xpage similar to how the dialog would appear. Once you have that working then you should be good to apply to dialog. This idea is to just take the dialog out of the equation first to make sure it works normally.
Instead, I decided to open the dialogs using CSJS, instead of SSJS. I've changed some of logic, and will have a bit more to do to finish this part of the project. Thanks to all!

XSP.showDialog doesn't work in onStart event?

I have the following test XPage.
<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core"
xmlns:xe="http://www.ibm.com/xsp/coreex">
<xp:panel id="pagePanel">
<xp:text escape="true" id="didThePageCompile">
<xp:this.value><![CDATA[#{javascript:var d = new Date();
return d.toLocaleString();}]]></xp:this.value>
</xp:text>
<xp:br></xp:br>
<xp:button value="Label" id="button1">
<xp:eventHandler event="onclick" submit="true"
refreshMode="partial" refreshId="dialog1"
onStart="XSP.openDialog('#{id:dialog1}')"
onComplete="XSP.closeDialog('#{id:dialog1}')">
<xp:this.action><![CDATA[#{javascript:var agent = database.getAgent("runLongTime");
var response = agent.run();
// var d = getComponent("dialog1");
// d.show();
}]]></xp:this.action>
</xp:eventHandler>
</xp:button>
<xe:dialog id="dialog1" title="Test Dialog">This is a test dialog</xe:dialog></xp:panel>
</xp:view>
The agent "runLongTime" just sleeps for 10 seconds. This works fine. When I click the button however the dialog box does not show up. I checked the source and it generates the correct code, and that code works when I manually put it into the console.
I don't get any errors and the agent executes fine. I've also tried changing the refreshId to "pagePanel", but still the same.
XSP.openDialog() and XSP.closeDialog() each trigger a partial refresh. The XPages client-side API includes logic for preventing multiple partial refresh operations from executing in parallel, which is likely preventing your dialog from displaying because by the time it attempts to run the refresh to show the dialog, it's already running your button event.
Add a JSON-RPC (called "Remote Services" in the control palette) to the page. Move your button's server event code to a method of the RPC. You can then change the button event to be purely client-side: call XSP.openDialog(), then call the RPC method and close the dialog in the onComplete of that method. This should prevent the race condition you're currently experiencing.
as far as I can see here, you are trying to open/close the same dialog.
Some days ago I got the same issue and wondered why this was not working.
Finally I checked the events and ended with the spectacular result that onStart and onComplete fired up almost parallel.
Maybe you could try to insert a timeout (window.timeout) before calling the XSP.closeDialog event.

ExtLib Mobile Controls - How to build a button to switch to an appPage

I'm working on an XPage for mobile users for an existing application. I want to use the mobile controls from the ExtLib for this.
I've build an XPage with a SinglePageApp and some AppPages on it. Now I want to build an AppPage with a search menu, a simple inputText and a button to start the search.
The inputText is bind to a sessionScope variable. I want to use the variable in a second appPage to get the search value and show a filtered/searched view.
The problem is the button. I'm not sure how to build this button to move to the other appPage. This is my last attempt, which fails with a runtime error.
Any idea how to get this running or what's wrong ?
Kind regards
Ingo
<xe:appPage id="appPage34" pageName="searchPage" preload="true" resetContent="true">
<xe:djxmHeading id="djxmHeading34" label="Search..." back="Home" moveTo="home">
</xe:djxmHeading>
<xp:inputText id="searchInput" value="#{sessionScope.searchValue}">
</xp:inputText>
<xp:button value="Search" id="button1" refreshMode="complete" type="submit">
<xp:eventHandler event="onclick" submit="true">
<xp:this.action>
<xe:moveTo targetPage="#searchResult"></xe:moveTo>
</xp:this.action>
</xp:eventHandler>
</xp:button>
</xe:appPage>
What does the runtime error say?
If you can not get to the XPages log files on the server directly, then use XPages Log File Reader from OpenNTF to get easy access to the log files from a browser.
Does it work if you use "searchResult" as the value for targetPage (assuming the appPage is called "searchResult")?
I've now come to a solution with a static line item instead of a button, since I couldn't get the button working. I think it has something to do with the way the single page application handles the access to mobile pages.
The search page looks like this :
<xe:appPage id="appPage34" pageName="searchPage" preload="true" resetContent="true">
<xe:djxmHeading id="djxmHeading34" label="Search..." back="Home" moveTo="home">
</xe:djxmHeading>
<xp:inputText id="searchInput" value="#{sessionScope.searchValue}">
<xp:eventHandler event="onblur" submit="true" refreshMode="complete">
<xp:this.action>
<xp:executeScript>
<xp:this.script><![CDATA[#{javascript:var svalue = getComponent("searchInput").getValue(); sessionScope.put("searchValue",svalue);}]]></xp:this.script>
</xp:executeScript>
</xp:this.action>
</xp:eventHandler>
</xp:inputText>
<xp:br></xp:br>
<xp:br></xp:br>
<xe:djxmLineItem id="djxmLineItem41" label="Start Search..." moveTo="#searchResult">
</xe:djxmLineItem>
</xe:appPage>
In the mobile page for showing the search result I simply get the value of the sessionScope variable, issue a full text search with the value and use the resulting document collection in a repeat control.
I still would rather use a button because the static line item is not really what a user expects as a gui element to start the search. But at least this is working.

Disabled Check Box Loses Value When Saving

I have a check box that is disabled. I click a button that sets the value of that check box to be 'checked'. When I go to save, the check box loses its value. Anyone have any ideas? Here is a simple mockup:
<?xml version="1.0" encoding="UTF-8"?>
<xp:view
xmlns:xp="http://www.ibm.com/xsp/core">
<xp:this.data>
<xp:dominoDocument
var="MainForm"
formName="MainForm" />
</xp:this.data>
<xp:checkBox
text="CheckBox"
id="CheckBox"
value="#{MainForm.CheckBox}"
disabled="true"
checkedValue="Y"
uncheckedValue="N">
</xp:checkBox>
<xp:br></xp:br>
<xp:button
id="setBc"
value="Set CheckBox">
<xp:eventHandler
event="onclick"
submit="true"
refreshMode="partial"
refreshId="CheckBox">
<xp:this.action><![CDATA[#{javascript:getComponent("CheckBox").setValue("Y");}]]></xp:this.action>
</xp:eventHandler>
</xp:button>
<xp:button
value="Save"
id="button5">
<xp:eventHandler
event="onclick"
submit="true"
refreshMode="complete">
<xp:this.action><![CDATA[#{javascript:MainForm.save();}]]></xp:this.action>
</xp:eventHandler>
</xp:button>
</xp:view>
Disabled controls are not included in page submissions.
You can combine your disabled check box with a xp:inputHidden control which is a hidden input field that is included in page submissions.
This could be a specific problem to Domino 8.5.3 (if that is what you are using).
We have noticed that since we upgraded to 8.5.3 we get a problem (on normal classic domino pages) where fields tagged as "disabled" don't get saved down to the doc.
We have had to build around this by not using a "proper" field that is disabled for values that has to later be saved.
Another workaround was to remove the disabled setting before posting in the post script.
We are fairly sure this all started to happened with the release of 8.5.3

Resources