One of my colleagues has been working on an XPages application and, because of other requirements, was creating his own modal dialog for taking action on a particular entry in a view.
First, it’s worth a bit of background if this is something you’ve needed to do but are not sure how to. My usual method is to add a button to the row in e.g. a Data View, which runs SSJS / Java to set a viewScope variable with the current entry’s NoteID and load the dialog. Because we want to act on the right document from the dialog and after the dialog has been closed, we need to serialise a pointer to the relevant document on the server side, for which viewScope is the natural place. The dialog then prompts for some kind of entry or action, which runs SSJS / Java and uses that viewScope variable to identify which document to process after, if processing is successful, clears the viewScope variable, closes the dialog and refreshes the view.
The ability to call the dialog via SSJS / Java is an extremely useful piece of functionality. And to the layman, the assumption is that all that’s happening is a partial refresh to run SSJS and load the dialog, then another partial refresh to close the dialog at the end.
But reproducing that same functionality in a manually coded dialog was not updating the view, even though the refreshId was set to the dataView, same as the second parameter of the dialog.
After some investigation and proving it worked for the normal dialog, the answer became clear thanks, as ever, to a PhaseListener along the lines of this XSnippet from Tony McGuckin. (In my case, I’ve been using PhaseListeners since early in 2012, so I’ve got a slightly different one.)
It turns out that assumption of a layman (and I was one of those until today) is wrong, as the PhaseListener proves. This is what appears when you click on a button to launch an Extension Library dialog via SSJS / Java:
All six phases of the lifecycle trigger, then Phase 1 and 6 trigger again. The same happens when closing the dialog passing a refresh ID.
Investigating the code makes everything clear (which is another reason why open sourcing more of the XPages runtime would benefit developers). The UIDialog class’s show() method runs this code:
The hide() method runs similar code:
XSP.closeDialog(). This directs us to the code in Dialog.js. Looking at that, we see both trigger an
XSP.partialRefreshGet. So the SSJS is returning CSJS which is triggering a partial refresh.
This explains the extra logging of Restore View and Render Response phases. It also explains why the updates to the view are displayed when closing an Extension Library dialog. The partial refresh you code in your XPage makes your updates and returns CSJS, which calls a partialRefreshGet to reload the view entries for the current page (NotesXspViewEntries cannot be serialised, so every refresh has to get the view entries again) and update the HTML on the page with the changed details.