I have an XPage with some SSJS code that I'd like to execute in the case of a complete refresh. (It's also okay if it executes on initial page load, I guess.) If a partial refresh of a component on the page has occurred on the page, then I don't want the code to execute. Is it possible to distinguish these cases? It feels like I need to set a state variable in viewScope to be able to do this.
For context, the partial refresh is a user clicking on the links of a pager to move through chunks of view elements. The intitial/complete refresh case is performing a FTSearch on the view. That should only be done when the user clicks on other links on the page that are used to filter the view.
The XPages lifecycle and event handlers are still a mystery in some ways.... Thanks in advance!
Add your SSJS to the beforePageLoad or afterPageLoad, depending on what's available). Those events are only triggered during the initial page load, which you can see by adding print("Running beforeRenderResponse"); to the event and looking at the server console.
In events where you want to run the code again, use context.reloadPage(); at the end.
The same XPages lifecycle is processed for refreshMode="partial" and refreshMode="complete".
Related
If I use
context.redirectToPrevious()
It works great, but If I call an xagent with or without state between opening the document and doing a close of the document. I end up navigating to the xagent.
And If I go directly to the view behind I loose opened categories in the view.
Is there a way to block an xpage to end up in the navigation/history tree?
There are two approaches that would work.
The first is to use client-side JavaScript to open the XAgent. How you handle that will depend on whether there are values set in the browser that you are passing to sessionScope for the XAgent to use. If not, you can just use client-side JavaScript to open the relevant XAgent page. If you do need values, there are two options:
Pass them as query string parameters to the XAgent instead of storing them as sessionScope variables.
Perform a partial refresh to store the values in sessionScope and open the XAgent page via client-side JavaScript either in the onComplete() event (will trigger every time) or using view.postScript(), passing the relevant CSJS as a string (will only trigger if validation is successful).
The second is to set the previous page in the beforePageLoad event and then use that value in context.redirectToPage().
I have a strange thing occurring; as usual, I can't post code, unfortunately, so I'm describing the problem in case anyone can suggest a possible cause.
I have an xpage with a custom control included on it; the custom control handles document locking and changing to edit/read-only modes via links. The document locking is done by setting an applicationScope variable based on the UNID. To make it more friendly for other users on the system, I run a function periodically on the page to check whether the document is locked or not and update a link/label/tooltips appropriately (e.g. if locked by another user, then the "Edit" button is disabled; when the lock is released, it's re-enabled). This is done by calling an "xagent" through a standard, simple dojo-based ajax call.
For some reason, the behavior of the system gets erratic after 45 seconds to a minute. I'm checking the lock status every ten seconds or so, so it's not happening with the first call. I'm displaying a list of records associated with the document; each record is a row in a repeat. When I first go into edit mode, the controls are all displayed as they should be, i.e. editable. If the user changes a particular value with a combobox, it updates the whole row with a partial refresh. When things get erratic, I noticed that the row starts refreshing in read-only mode, which suggests to me that the document is changing edit mode. The only time I knowingly change edit mode is if a "Cancel" or "Save" button is pressed. (The locking mechanism itself doesn't have anything to do with the edit mode.)
It certainly seems like the ajax call I'm making is at the root of this. But I've stripped the xagent and the client-side code down to practically nothing, and it's still happening. I can't see what would be causing this behavior. Can anyone hazard a guess? Thanks....
Maybe check if the server log file has warnings like:
WARNING CLFAD####W: State data not available for /page because no control tree was found in the cache.
If you're seeing those warnings, it could be that the server can no longer find the current XPage page instance in the cache. In that case the page will revert to the initial state, like when the page was first opened. That might be why the document goes to read-only mode.
The session cache of server-side page instances only holds 4 pages when xsp.persistence.mode=basic, or it holds 16 instances when xsp.persistence.mode=file or fileex.
If you load 4 xagent page instances, then that will fill the cache, and it will no longer be able to find the page instance for the current XPage you are viewing. So the XPage will stop performing server-side actions, and partial refresh will always show the initial state of that area of the page.
To avoid that problem, in the xagent page you can set viewState="nostate" on the xp:view tag, so that page instances are not saved for the xagent page, as described here:
https://tobysamples.wordpress.com/2014/12/11/no-state-no-problem/
Or else you can create and reuse one page instance for the xagent, so only one is created. That is, on the first call to the XAgent, have the xagent return the $$viewid value for the xagent page instance (#{javascript:view.getUniqueViewId()}), and then in subsequent requests to the xagent use that $$viewid in the request, to restore the existing xagent page instance instead of creating new instances that will fill the cache. So the subsequent xagent requests will be like so:
/myApp.nsf/xagent1.xsp?$$viewid=!aaaaaaaa!
It's hard to troubleshoot without code, but here are a few thoughts:
How are you checking document locking? Via a client-side JavaScript AJAX call or an XPages partial refresh? If the latter, what is the refresh area? If the former, what is the refresh area you're passing and the return HTML? Does it always occur when you're in edit mode on a row and the check happens, or independently of that? The key thing to check here is what the check for locking is doing - is it checking the server and returning a message outside the repeat, or checking the server and returning HTML that overwrites what's currently on the browser with defaults, e.g. the document mode as read mode.
What network activity is happening between the browser and the server and when? Is something else overwriting the HTML for the row, so resetting the row to read mode.
It's unlikely to be random, the key is going to be identifying the reproduceable steps to identify a common scenario/scenarios and cause.
EDIT
Following on from your additional info, is there a rendered property on the Edit link? If that calculates to false in earlier JSF lifecycle phases, the eventHandler is not available to be triggered during the Invoke Application phase. Because the eventHandler also includes the refreshId, there is no refreshId and refreshMode, so it defaults to a full refresh with no SSJS running. See this blog post for clarification http://www.intec.co.uk/view-isrenderingphase-and-buttons/.
I asked this question a couple months ago, but there has been no response so I thought I would try again. I have a block of SSJS that manipulates a number of values. There are some computed fields that are impacted by these changes and they do not display correctly. I have a refresh button on the XPage and it does a partial refresh after which everything works fine. I need to somehow trigger a partial refresh on the a specific item (a panel in this case) as the last step in the afterPageLoad in the SSJS.
Any ideas?
Thanks
Refreshing Panels from SSJS without a button, link or something like that is a bit tricky.
But i think your problem is more located in the order in wich you are trying to compute your fields what about triggering your Code in a erlier event before those Fields are rendered, to avoid displaying the wrong values in the first place, maby post some example Code.
If you only want to refresh a the panel again after the page has bean loaded try this in the onClientLoad ClientEvent this could also fix it:
<xp:eventHandler event="onClientLoad" submit="false">
<xp:this.script><![CDATA[dojo.ready(function(){
XSP.partialRefreshGet('#{id:yourPanel}',{})
});]]></xp:this.script>
</xp:eventHandler>
I have a Xpage that performs a partial refresh when a user selects a value in a combobox (onChange event). The combobox is actually a filter selector for a custom view component.
This event triggers some SSJS code and performs a partial refresh. This event breaks occasionaly, probably due to XPages session being removed.
The partial refresh is executed but the SSJS code that sets the viewScope variables is no longer executed. This results in the view showing all data without filter applied.
I added a print statement as the first line of the ssjs function. This print statement no longer executed.
I managed to reproduce this by restarting http with the page open.
Looking at the network tab in Chrome devtools shows status 200 on the partialRefreshPost. Also the partialrefresh id seems correct.
Any explanation?
This happens if the session times out, the server was restarted and/or the the application was rebuild.
If a partial refresh is then posted to the server, it is like a HTTP GET based request: The persisted view of your current XPage is "waked up again" but some the JSF lifecycle phases are skipped (3, 4, 5). SSJS code for partial refreshs is executed in the skipped phases, that's why there is no print out on your console.
[This is a very short explanation. For more information please check the XPages Master Classes Videos about the JSF lifecycle and it's details]
I've set my button to 'Submit'. The XPage is set to stay on the same page if save is successful. How do I create a messagebox to inform user the save is successful?
There are a number of options you can consider. A msgbox is the least desirable.
You could add an information message on top of the form that either fades after a few seconds or on change. The custom control would show when you set a viewScope variable (e.g. viewScope.saveSuccess ) and have a visibility formula for it. It also would register an event listener to hide when a field is altered. You also could consider redirecting to a different page.
This post already asks a similar question to do with how to call a client side script from server side, could be useful.
client message after SSJS routine how?
Here are two examples that I have used as inspiration to create a custom control for error messages and for info messages such as what you are asking for:
http://openntf.org/XSnippets.nsf/snippet.xsp?id=ssjs-form-validation-that-triggers-errormessage-controls
http://lotusnotus.com/lotusnotus_en.nsf/dx/xpages-tip-a-simple-cc-for-prompting-ssjs-messages-to-ui....htm
The easiest way to call csjs after running ssjs is to add code the event handler's onComplete event. The onStart, onComplete, and onError events run client side js before or after your ssjs, but are only executed during a partial page refresh.
The simplest way is to add this line of code (or the CSJS you prefer) in the postSaveDocument event:
view.postScript('alert("Document saved")');