XAgent breaks previous navigation - xpages

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().

Related

Execute XPages SSJS code if complete refresh, not partial refresh?

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".

Xpages equivalent to Database Script initialize

I am running Xpages in XPiNC.
My usual pattern for an Xpages app is to have a xpHome.xsp page that is set to be the first page that is opened. In this I page I set any scope variables that are at the application level, then head to the "real" first page.
Now I have run into a problem. My current database will send out emails when a status changes, and this will include a doc link to the document, which points to the correct Xpage to open. However, because the user is not going through the home page, then my applicationScope vars are being set.
I thought I could fix this by setting a semaphore in the initApp function - the last thing it would do is to place a "Y" in an applicationScope.semaphore field. So when I open my Xpage the first thing it does is check for that, and if it is null, then I call the initApp function.
For some reason this is not working. But even so I would like to find the equivalent of the old database script "Initialize" event. Something I can call whenever the db is opened for the first time.
How do others handle this problem?
Create a managed Java bean "app" which
works on application scope
sets all application parameters
offers all application parameters
Access the bean with app.xxx in EL or Javascript or call methods directly like app.getXxx() or app.doWhatEverYouWant() in JavaScript.
The bean "app" gets initalized automatically when one of the methods gets called first time.
You can find an example here for start or google for "XPages managed beans" for more Information.
Yes, you have to switch your current code partly to Java but it should be worth it in the long run.
If you want to or have to stay with JavaScript then initialize your application scope variables in a custom control which is included in every XPage like layout.xsp in beforePageLoad event.
Use an additional variable applicationScope.initialized. Check if applicationScope variables aren't initialized yet in JavaScript with
if (!applicationScope.initialized) {
... initialize your applicationScope variables ...
applicationScope.initialized = "yes";
}

Xpages document changing document mode?

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/.

XPage not syncing properly with backend data on partial refresh

I have an XPage that displays fields in a document. I also have the ability to pop out a new window that displays those same fields. I'm implementing a document locking scheme so that the two instances can't cause conflicts (and this is how I'm testing it).
A problem I've run into is that when the user edits the document in the pop out and saves it, a partial refresh of the panel containing those same fields in the original page doesn't show the updated data.
The save in the pop out was successful, and I can see in the Notes client that the document does indeed have the new value, but the original page simply won't show the new value. A complete page refresh using the reload button in the browser works, but I'd like to trigger this programmatically and as quickly as possible, hence the partial refresh.
Does anyone know what is going wrong? Is the NotesXspDocument in the original page getting out of sync with the backend document? I read about document1.getDocument(true), but that doesn't seem to do anything.
(As usual, I can't supply source code unfortunately....)
Once the NotesXspDocument is loaded with the XPage, a partial refresh does not update the xspDoc from the back-end DB, but from the in-memory DataSource.
You will need to refresh the XPage:
Reload the url from browser or in ssjs with a context.reloadPage()

Changes to DOM objects are lost after partial update

On a page I have some fields that I want to be "readonly" (in my meaning they can't be accessed but they will store values, read earlier question in this matter if issues...).
I use a client JS setting these attributes on page load:
$(".readonly").attr('readonly', true);
If I have a partial update on any of these fields the attribute is lost and the field is accessible.
What is the best practice to overcome this and make it work?
Every partial refresh has a oncomplete method bound to it. What you could do is add code to the oncomplete method so the item is being set readonly again. Another, better, approach would be not to change the attribute clientside but to have hidden fields which are used to store the data.
When you have an event bound to for instance an Link control you can change the oncomplete code by clicking in your source pane on the event tag. When you browse the events section in the properties pane you will see the onComplete, onError, onStart properties. You can add your own clientside script in these properties.
Before trying to overcome the "problem" You shoud try to understand what exactly partial refresh do and where the state of application is kept.
Unfortunately partial refresh is replacing current html content (or rather part of it) with a newly created one and only form fields that has backing controls will keep state.
I suggest You should try setting readonly property on controls which You would like to make readonly (if there is some logic here You can always use ssjs).
Optionally You can try to preserve the state on the client side by using csjs global variables but this is rather hard to manage.
And one more thing - try to use the technology to solve the problem(xpages) and try not to hack Your way through with use of stuff that You accidentally know (jquery).
I would agree with jjtbsomhorst on using onComplete event. But another alternative could be setting the readonly property via code like this:
var textField:com.ibm.xsp.component.xp.XspInputText = getComponent("inputText1");
var readOnlyAttr:com.ibm.xsp.complex.Attr = new com.ibm.xsp.complex.Attr("readonly", "readonly");
var list:java.util.ArrayList = new java.util.ArrayList();
list.add(readOnlyAttr);
textField.setAttrs(list);
You could call this on the afterPageLoad event of the XPage. But I really don't know whether this would be the best way to about!

Resources