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.
Related
is it possible to call a Dialog component in typeAhead functionality?
What i want to do is If the user enter a word which does not come up with typeAhead function then a dialog should appear on the screen.
Please find my code below (my dialog is in custom control)
Regards
Cumhur Ata
<?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">
<xe:dialog id="dialogConfirmation">
<div class="modal-body">
<p>You have entered a word which is not in the list</p>
<p class="text-warning">Please add/or cancel<small> </small></p>
</div>
<xe:dialogButtonBar id="dialogButtonBar1">
<xp:button value="Hayır" id="btnConfirmYes">
<xp:eventHandler event="onclick" submit="false">
<xp:this.script><![CDATA[XSP.closeDialog('#{id:dialogConfirmation}')]]></xp:this.script>
</xp:eventHandler></xp:button>
<xp:button value="Evet" id="btnConfirmNo" styleClass="btn-primary">
<xp:eventHandler event="onclick" submit="true"
refreshMode="complete">
<xp:this.action><![CDATA[#{javascript:openNewFrm(sessionScope.extDbPath,sessionScope.expDbPage)}]]></xp:this.action>
</xp:eventHandler>
</xp:button>
</xe:dialogButtonBar>
<xe:this.title><![CDATA[#{javascript:var c = "Warning";return c;}]]></xe:this.title></xe:dialog></xp:view>
You can hijack the result of the typeahead and call your dialog if it's empty by using this snippet:
https://openntf.org/XSnippets.nsf/snippet.xsp?id=typeahead-onstartoncomplete-event
I don't have Domino Designer at hand right now so I can't try this out. So this is just guessing:
I don't think that you can use the standard Edit Box control's type ahead feature for something like that; instead you could program this yourself using the control's "onkeyup" event, mimicking the standard type ahead. the idea is that a classic type-ahead operates as a filter to a list of possible entries, just like a "getElementsByKey" method that is fired upon each key stroke. So with every event you check what's in the Edit Box so far, compare it to your list, then display the filtered result to the user in a pop-up (you may want to use a dojo tooltip here).
If the result is null you can bring up your dialog instead.
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.
The scenario:
Clicking on a link, I'm accessing an xpage, let say: start.xsp.
I've added the following script to this .xsp:
<xp:scriptBlock id="scriptBlock1">
<xp:this.value><![CDATA[
XSP.addOnLoad(function(){
XSP.openDialog("#{id:dialogSearch}")
});
]]></xp:this.value>
</xp:scriptBlock>
So, every time this .xsp is loaded, a dialog is showing up. The problem is the current start.xsp is being refreshed/loaded many times, considering the fact that the xpage have numerous fields/controls on it. It is uncomfortable every time this start.xsp is loaded / refreshed the dialog to show up.
Is it possible to show the dialog after the start.xsp is loaded but ONLY when the above link was clicked? I do want firstly to go to that xpage and after this to show the respective dialog.
Thanks for your time.
Set a session scope variable in your link
<xp:link
escape="true"
text="Link"
id="link1">
<xp:eventHandler
event="onclick"
submit="true"
refreshMode="complete">
<xp:this.action><![CDATA[#{javascript:
sessionScope.showDialogSearch = "yes";
context.redirectToPage("start.xsp")
}]]></xp:this.action>
</xp:eventHandler>
</xp:link>
Add a rendered attribute to your start.xsp's xp:scriptBlock
<xp:this.rendered><![CDATA[#{javascript:
var show = sessionScope.showDialogSearch;
sessionScope.remove("showDialogSearch");
return show
}]]></xp:this.rendered>
This way dialog is only be shown if start.xsp was executed from your link and only once because it gets deleted at first use in rendered attribute.
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.
Below is a simple Xpage with a radiobuttongroup that is bound to a sessionScope variable. The onclick event of the radio button group sets the computed field. There is an afterPageLoad event to initialize the session scope variable.
All works great. However, if I clear the session Scope variables (using the debug custom control) then the onclick event never fires. The user can click on the radio button all they want and the computed field never changes until the page is reloaded by pressing F5. Below is my page source. Any suggestions on how to get the onclick event to fire? This would be a big usability issue if the user let the session variables time out and then starting clicking on the radio button.
Howard
<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core">
<xp:this.afterPageLoad><![CDATA[#{javascript:print("starting the afterPageLoad event");
if (sessionScope.init != true|| sessionScope.radioData == null){
//setup default values'
print("initing the value");
sessionScope.init = true;
sessionScope.radioData = "Red";
}
}]]></xp:this.afterPageLoad>
<xp:radioGroup id="radioButtons" value="#{sessionScope.radioData}">
<xp:selectItem itemLabel="Red"></xp:selectItem>
<xp:selectItem itemLabel="Green"></xp:selectItem>
<xp:selectItem itemLabel="Blue"></xp:selectItem>
<xp:eventHandler event="onclick" submit="true"
refreshMode="partial" refreshId="computedField1">
<xp:this.action><![CDATA[#{javascript:print("starting onclick event");
if (sessionScope.init != true){
print("reload the page");
context.reloadPage();
}
var radioval = getComponent("radioButtons").getValue();
getComponent("computedField1").setValue(radioval); }]]></xp:this.action>
</xp:eventHandler></xp:radioGroup>
<xp:text escape="true" id="computedField1"></xp:text></xp:view>
I've seen this same behavior several times in my own xpage apps, and I've found that the problem happens only for partial page refreshes where the target refreshId is not large enough in scope to reload all of the data needed by the control. When I change the refreshId to the page's main div (or use full page refresh), then all works as expected.
I think that it's the call to location.reload in the client-side code which is actually fixing your issue. I'd be interested to learn if increasing the scope of refreshId also fixes the problem.