Xpage, createForm=false disables SSJS events on links? - xpages

I ask this just to be clear here: I accidently set the createForm property to false. I then expected a link event that should open another page only not to function any more.
Is this the intended behavior of SSJS events e.g. in links when you disable form creation?

As Per mentions, all events require a form: if they are full refresh, then the page needs a form to post to in order to trigger the redirect; if they are partial refresh, the form determines the contents of the AJAX POST.
The XPages runtime includes support for a form component, but it is not included in the component palette (and it cannot be added via Designer Preferences), so the only way to add it to a page is by editing the source XML directly. For example:
<xp:form>
<xp:link id="exampleLink" text="Example Text">
<xp:eventHandler event="onclick" submit="true" refreshMode="complete">
<xp:this.action><![CDATA[#{javascript:// event code}]]></xp:this.action>
</xp:eventHandler>
</xp:link>
</xp:form>
There are (at least) two reasons why this component is useful:
It can improve performance. If a page contains different areas that are functionally distinct -- in other words, an event in one portion of the page does not need to be aware of data in any other portions of the page -- then wrapping each section in a separate form component causes each event to only post data that is contained inside the same form as the component that triggers the event. Your question indicates that the link that broke when you set createForm to false should navigate the user to another page; it's likely, therefore, that this event doesn't need to know about any field values, because the user is leaving the current page anyway. If that's true, wrap this link in its own form, and any fields inside a separate form, and the link will perform marginally faster because the browser doesn't have to post any field data... just the identifier for the link itself.
It can provide style flexibility. It's common for a developer to receive, separately from the actual end user requirements, pre-determined CSS from a designer unfamiliar with Domino -- for instance, if the site design is outsourced, or must adhere to corporate style guidelines. This often becomes a source of tension when the designer has made certain assumptions that, at first glance, are incompatible with the markup that Domino generates. One of the most common examples of this is when the site contains search features, because most web developers will have one form for search and a separate sibling form for any other fields. This can increase the cost of a project when either the designer or the developer has to revise a stylesheet that the designer already developed to account for a single form tag surrounding all the content. In short, suppressing the default form element and explicitly specifying form components where needed makes it easier to adhere to externally imposed style guidelines.
So there are many use cases where it's actually preferable to use one or more form components on an XPage... just remember that all data and events must be inside a form -- whether the default form that usually surrounds all the content, or a manually included form component -- and that forms cannot be nested. You can add as many form components as you want, but they must be siblings. No form can contain another form.

Yes, because you are doing HTTP POST requests and they require a form.
You can convert your POST request link to a GET request link instead be removing the SSJS event and creating a "basic" link instead:
<xp:link escape="true" text="Link" id="link2" value="/somepage.xsp"></xp:link>
But if you need the SSJS logic, then you also need to have a form.

Related

Pass parameters to a computed custom control

I'm using the xp:include tag for displaying custom controls according business rules.
I configured my custom controls with parameters (the custom prperties) that I used through the compositeData syntax.
My question is :
How can I declare the computed xpages for passing arguments to my custom control ?
Switch control or Dynamic Content Control may be a better option to choose. The difference is Switch control loads all facets into the component tree, Dynamic Content Control only loads the current facet to be displayed. So if they're specific to different parts in the business process, Dynamic Content Control may be more suitable.
Alternatively, use different XPages for different stages in the business process. With XPages links from views can be computed to go to a specific XPage rather than a single one defined for the form.

xe:breadCrumb Use Without Tree Nodes?

I have an XPages app with a page > sub-page structure that is defined by URL parameters prior to our company's adoption of Domino 8.5.3 UP1. Now that we do have UP1, I've been eyeing up the xe:breadCrumbs control with a little bit of envy. Not being familiar with xe:pageTreeNodes (which I know at least exist thanks to my copy of XPages Extension Library), I figured I'd "phone a friend". I couldn't find much on the topic. My question is two-fold:
How should one implement page tree structure to use properly with the xe:breadCrumbs control?
With my current setup (root page being standard page parameter, sub-page being a second, custom parameter), how easily can I use my setup with xe:breadCrumbs?
At some point, I'm more than willing to cut my losses and just build out a quasi-breadcrumbs element with some computed xp:link controls in a div. Since the opportunity arose, I figured I would check and see if there were some better options. I know this is a little vague, but I think the idea is communicated here.
[Edit:]
I should probably ask if this is something more directly and exclusively used with the xe:navigator. If that's the case, then I may be a little more sad, but a bit less confused.
[/Edit]
Tree nodes are fine. Here is small example. Prerequisites:
all documents are in the same database. Not a big issue, just update href params accordingly.
Document contains fields with ID and Label (subject, title) of parent documents (all levels)
There is view "id" containing only one column sorted by document's id to open it (Domino syntax) - see also: native Domino links and XPages
dds is curent document's datasource
ddsParent is parent document's datasource
<xe:breadCrumbs id="breadCrumbs1">
<xe:this.treeNodes>
<xe:basicLeafNode label="Top document: ${dds.fld_TopLabel}">
href="/id/${dds.fld_TopID}">
</xe:basicLeafNode>
<xe:basicLeafNode label="Sub1: ${ddsParent.fld_Label}">
<xe:this.href><![CDATA[#{javascript:"/0/" + ddsPonuka.getDocument().getUniversalID()}]]></xe:this.href>
</xe:basicLeafNode>
<xe:basicLeafNode label="Current level: ${dds.fld_Label}">
</xe:basicLeafNode>
</xe:this.treeNodes>
You have to alter this for every XPage. Sure, you can make it a custom control with parameters, but you will end up with custom control on every XPage fed by parameters roughly in the same structure.
The best option is to make managed bean configurable in some sort and returning ExtLib tree objects. Then your source will be reduced to:
<xe:beanTreeNode nodeBean="my.bean.Class"></xe:beanTreeNode>
Best example is XPagesExt.nsf bundled with ExtLib distributions.

learning how to use xe:dominoViewEntriesTreeNode

I realized my question was too vague on adding navigation items dynamically, so I am rewriting the question.
I have discovered the xe:dominoViewEntriesTreeNode control from the xpages. I think I can use this to add navigation items to the navigator control based on entries in the view.
I am struggling to find very much in the way of documentation or resources that break down how to do that. Can anybody to me to a good reference or example code?
You can use dominoViewListTreeNode to build a menu based on views in a database (and not documents in those views).
Here is an example of using xe:dominoViewListTreeNode to dynamically build a menu based on all views called "Test*" (using regex in the filter property). When selecting a menu item from the menu, the name of the view is submitted to the server (using EL notation for the viewEntry.getName() method).
The example also contains an onItemClick event handler that "catches" the name of the view as the submitted value and stores this in a sessionScope variable. The event handler then redirects to a views.xsp XPage that could contain a Dynamic View Panel control where you could use the sessionScope variable to control what view to show.
The sessionScope variable is also used to mark the selected menu item as "selected".
<xe:navigator id="navigator1">
<xe:this.treeNodes>
<xe:dominoViewListTreeNode filter="Test.*" submitValue="#{viewEntry.name}" var="viewEntry">
<xe:this.selected><![CDATA[#{javascript:viewEntry.getName() == sessionScope.clickedView}]]></xe:this.selected>
</xe:dominoViewListTreeNode>
</xe:this.treeNodes>
<xp:eventHandler event="onItemClick" submit="true" refreshMode="complete">
<xp:this.action>
<![CDATA[#{javascript:sessionScope.clickedView = context.getSubmittedValue();
context.redirectToPage("views.xsp");}]]>
</xp:this.action>
</xp:eventHandler>
</xe:navigator>
Instead of the onItemClick method to redirect to an XPage, you could compute the href property of xe:dominoViewListTreeNode to return the name of an XPage.
I have a short presentation called "XPages Extension Library - Create an app in 1 hour (almost)" that presents this technique (and other techniques).
I assume you have an area on your page carrying the navigation items, e.g. links to some pages with link texts?
I would then use a repeat control with a datasource/javascript source that returns the document item values from your profile document or something.
If you are not into repeat controls then you should consider to read this: http://xpageswiki.com/web/youatnotes/wiki-xpages.nsf/dx/Work_with_repeat_controls
On this page there is also a sample dealing with a profile document.
By the way: using profile documents was always a crutch, so consider to youse "normal" config documents instead.

Can you compute which custom control to use?

Think "computed subform", but in Xpages.
On one of my custom controls, depending on a certain value, I want to either present a custom control that renders a drop-down list using a combobox or renders an input box with a type-ahead.
This is on a custom control that renders a view, with all view configuration choices handled by a document rather than design, so several different views utilize the same custom control.
For example: I have a By Status view using the custom control that has status as the first column and we use a combobox to allow the user to select which Status value to filter by. Another view is sorted by Requisition number and I want to use a type-ahead instead of the combobox.
My preference is to use the same dynamic view custom control for both and have a formula that determines which of the two (comboBox or inputText) to use. How do I compute which custom control to load?
(Credit for the dynamic view control goes to Scott Good's folks over at Teamworks Solutions.)
During it's life cycle, an XPage exists in two places. First of all a representation of the XPage's relevant components is stored on the server. Then the page goes through a lifecycle, retrieving properties from documents, checking which components should be rendered, retrieving the data for any repeating control such as a View Panel etc., and passing the relevant HTML to the browser. The browser is the second place it exists.
So you can't compute a custom control as such. All you can do is set the loaded property, and loaded needs to be based on a non-dynamic calculation such as a viewScope variable, the current XPage name, a view name stored on the XPage etc. What you would have difficulty doing would be using a different custom control based on data on that row entry.
The other option is the Dynamic Content control or Switch control from the Extension Library. Both are similar to using the loaded property, in that you're putting both custom controls on the page and choosing which to display.
From what you're describing, the loaded property should cover what you need.
Some time back I saw this question on StackOverflow where the author had used Include Page control (xp:include) to include custom controls using pageName attribute based on formula.
<xp:include>
<xp:this.pageName><![CDATA[${javascript:sessionScope.ccPageName + ".xsp";}]]> </xp:this.pageName>
</xp:include>
Similar to the technique described by Paul Withers in his answer the attribute of pageName is also computed on page load.

How to use xe:jsonRpcService?

I am trying to use the extension library component Remote Service (xe:jsonRpcService). I got some hints from here and here. Basically I am trying to save a document using RPC. The problem is that the document gets saved but it does not save any fields present on the XPage. Below is the sample XPage code:
<?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:this.data>
<xp:dominoDocument var="document1" formName="Test"></xp:dominoDocument>
</xp:this.data>
<xe:jsonRpcService id="jsonRpcService1" serviceName="service">
<xe:this.methods>
<xe:remoteMethod name="saveDoc">
<xe:this.script><![CDATA[print(">> " + getComponent("inputText1").getValue());
document1.save();
return true;]]></xe:this.script>
</xe:remoteMethod>
</xe:this.methods>
</xe:jsonRpcService>
<xp:br></xp:br>
<xp:inputText id="inputText1" defaultValue="testValue" value="#{document1.testField}"></xp:inputText>
<xp:br></xp:br>
<xp:button value="Save" id="button1">
<xp:eventHandler event="onclick" submit="false">
<xp:this.script><![CDATA[var deferred = service.saveDoc();
deferred.addCallback(
function(result) {
alert(result);
}
);]]></xp:this.script>
</xp:eventHandler>
</xp:button>
</xp:view>
What I have done here is that, I created Remote Service (service) where I am saving the current document (document1). It saves the document but does not save the value in inputText1. Also, when I try to print the value of inputText1 it shows on console but it is not getting saved.
Is this the right way to do it? Or am I missing something here. Also what would be some scenarios where usage of xe:jsonRpcService would be justified?
There are (at least) two reasons for avoiding the use of a JSON-RPC for this type of operation:
This service component is designed to be as lightweight as possible, so, unlike standard events in XPages (which automatically post the entire HTML form), it sends only the data required to call the method, and receives only the data returned by the method. In your example, the method takes no arguments, so it's literally just sending enough information for the server to know what method to call; similarly, you're just returning a boolean value, so that's literally all that will be sent back. If you use your browser's development tools (i.e. Firebug or the built-in tools in Chrome) to inspect the network traffic, you'll see this reflected in the JSON packets that are sent in each direction. As a result, the server doesn't "know" anything that you don't explicitly "tell" it. So it's faster than a typical event because you're not posting anything that isn't explicitly related to the method you're calling... but you have to intentionally send everything that the method does need in order to run.
Another side effect of the component's focus on performance is that it skips the component tree serialization at the end of the JSF lifecycle. If you're keeping the current page in memory, that shouldn't be an issue, but if you're using the default option (save all pages to disk), the server will "forget" any changes that are made to the page during the method invocation. You can explicitly override this behavior on a case-by-case basis by directly telling the view root to serialize its state, but it's easy to forget that you have to do this manually, which typically causes a lot of frustration when you see indications server-side that it's doing what it's supposed to but the actual web page doesn't reflect that. It's best to just treat any RPC method as a "read-only" operation unless you're certain you'll always remember this odd side effect and understand how to circumvent it.
My advice is to think of JSON-RPC as "SOAP minus the stupid". Phrased more politely, it's conceptually identical to Web Services, but without all the complexity of Web Services. As such, these types of services are ideal for data operations that are useful within the context of the current page without being explicitly tied to the state of the current page.
Here are some examples of operations where a JSON-RPC method might be useful:
Informing a new user whether the user name they're choosing for their new account is already taken. Instead of binding a standard keyup event which would post the entire form, send only the value of the one field to the service, query it against the site registration records, and send back a boolean.
Live polling of related data that is prone to frequent updates. Suppose you're developing a CRM, and you want to display the stock price of the company whose account you're viewing. Using setInterval to periodically ask the RPC for the updated stock price, then doing manual client-side DOM manipulation if the price changes, again allows you to perform a somewhat complex operation with a minimum of network overhead.
This doesn't mean that you can't use an RPC for write operations... but for any operation that needs a complete, up-to-date context (i.e. current value of every field on the current page) to run correctly, a standard event handler is nearly always the better approach.

Resources