Archive | Data Sources RSS for this section

XPages Tip: Filtering a View Data Source with URL Parameters

If you’re looking for a quick way to manipulate the data returned by a view data source, you can use URL parameters that match the property names. This allows you to effectively compute them without having to write code to compute the parameters. In this post, I’ll show several examples.

Sample View

In my sample database, I have a categorized view in the Notes client.

ViewDataSourceURLParams-1

I added a data source for this view to an XPages and dragged all of the columns on to the page to have it automatically create a view
panel.

http://www.server.com/myDB.nsf/MyPageName.xsp
ViewDataSourceURLParams-1b-XPage

Here’s the data source tag on the page — there are no computed properties.

<xp:this.data>
  <xp:dominoView var="view1" viewName="People"></xp:dominoView>
</xp:this.data>

Using URL Parameters to Filter the View

To filter the view, all you have to do is append URL parameters with the same name as a filtering property of the view data source.

To limit the data to a single category, add a categoryFilter parameter.

http://www.server.com/myDB.nsf/MyPageName.xsp?categoryFilter=Group 1
ViewDataSourceURLParams-2-categoryFilter

To execute a full-text search, add a search parameter. (The database must be full-text indexed or it will throw an error.) You can also include wildcards in the search parameter.

http://www.server.com/myDB.nsf/MyPageName.xsp?search=101
ViewDataSourceURLParams-3-Search

To filter the results based on the first sorted column in the view, use the keys parameter.

http://www.server.com/myDB.nsf/MyPageName.xsp?keys=Group 3

Other Actions

To set the view’s starting point, you can use the startKeys parameter. (Note: The view will continue on to the end after the starting point.)

http://www.server.com/myDB.nsf/MyPageName.xsp?startKeys=group 2

To expand or collapse categories in the view, use the expandLevel parameter.

http://www.server.com/myDB.nsf/MyPageName.xsp?expandLevel=1
ViewDataSourceURLParams-4-ExpandLevel

Miscellaneous Notes

These attributes work on the view data source and not specifically on the view panel, so it is useful on a repeat control or any other control that uses a view data source.

If your data source has ignoreRequestParameters set to true, then this will not work because it will – um – ignore the request parameters.

If you enter a parameter that doesn’t correspond exactly to a property name, then it will be ignored by the view data source.

Providing URL Parameters for Multiple Document Data Sources

You’re no doubt used to seeing URLs to open a document that look like this: http://www.server.com/db.nsf/myPage.xsp?action=openDocument&documentId=0123456789ABCDEF0123456789ABCDEF in XPages. The documentId and action URL parameters are used by each document data source by default. In this post, I’ll show how you can use the requestParamPrefix property to define a separate set of URL parameters for an additional data source.

By default, a document data source will use the documentId and action parameters to determine the document to open and the edit mode. However, if you have more than one document data source on a page, this may not be the behavior that you want.

For example, I have a database with a simple XPage that has two document data sources for the Person form.

<xp:dominoDocument var="document1" formName="Person"
  action="openDocument">
</xp:dominoDocument>
		
<xp:dominoDocument var="document2" formName="Person"
  action="openDocument">
</xp:dominoDocument>

If I open the page with a standard URL, both display the same document.

http://www.server.com/db.nsf/TwoDataSources.xsp?documentId=9E9324F079A7F31885257D06007ADF9C&action=openDocument

requestParamPrefix_1_SameDocument

If I change the action parameter to editDocument, then both change to edit mode. Sounds like a great way to generate a save conflict!

ignoreRequestParams

Of course, this isn’t really what I want. One option to work around this is to set the ignoreRequestParams property of the document data source to true and compute the documentId property (and, optionally, the action property).

<xp:dominoDocument var="document2" formName="Person"
  action="openDocument"
  documentId="#{javascript:return '0123456789ABCDEF0123456789ABCDEF';}"
  ignoreRequestParams="true">
</xp:dominoDocument>

This is the method that I am in the habit of using and it works well when putting the ID in a scope variable and using that for the computed property value.

The ignoreReuqestParams property tells the data source to ignore the documentId and action properties in the URL and leaves it up to you to manage them.

(Note: Even if you compute the documentId, it will not matter if you don’t set ignoreRequestParams to true; the URL parameters will still override the property value.)

requestParamPrefix

However, there is another way to handle this situation without computing the data source properties — the requestParamPrefix property.

You can set this on a data source and it will look for a separate copy of the documentId and action parameters and use them for that specific data source.

For example, if I set the requestParamPrefix to doc2_, then it will look for URL parameters named doc2_documentId and doc2_action and use those for this data source.

You can add the parameter directly in the page source or find it in the properties panel under All Properties > data > data > [data source]. (This assumes the data source is at the page level. If it’s on a panel, then that would be your starting point to find the data source properties.)

requestParamPrefix_2_requestParamPrefix

Now, I can open two different documents on the same page with a URL like this:

http://127.0.0.2/BlogTesting.nsf/TwoDataSources.xsp?documentId=9E9324F079A7F31885257D06007ADF9C&action=openDocument&doc2_documentId=01F564DFFEE4307A85257D06007AED1D&doc2_action=editDocument

requestParamPrefix_3_SeparateDocuments

With this approach, you do not need to set ignoreRequestParams to true. In fact, if you do, then the URL parameters will be ignored — even if they contain the specified prefix.

Dynamically Modify the Data Source on an Embedded Form in XPages

With inspiration from awesome XSnippet posted by Sven Hasselbach, I’ve found a much better way to work with embedded forms of related documents on an XPage.

Managing the Data Source with Scope Variables

I recently worked on an application that had a view of related documents embedded within a parent document page, along with an embedded form to work with the related documents. This concept applies to child/response documents as well as separate documents, related based on common piece of information. (By “embedded form”, I’m referring to a custom control with it’s own data source based on a separate Notes client form, displayed within the context of the parent page.)

As with any type of document data source, creating, viewing, and editing are the three types of data source actions.

By default, the embedded form is blank and can be used to submit a new related document. However, if the user clicks on a related document in the embedded view, they should have the ability to view or edit the selected document, based on their rights.

Along with the action, the document ID needs to be managed. It either needs to be blank (in the case of a new document) or set to the UNID of the document selected in the view.

Initial Implementation

The following steps were taken to implement this functionality:

  • Compute the data source’s action from a scope variable (defaulting to createDocument if no other variable was specified)
  • Compute the data source’s documentId from a scope variable
  • Set the data source’s ignoreRequestParams attribute to true
  • Set the links in the view to set the selected document’s UNID in a scope variable and also determine whether the form should be opened or edited and set the appropriate action in a scope variable (openDocument or editDocument, respectively)
  • Set the links in the view to trigger a partial refresh on the form panel in order to update the document in the embedded form
  • Set the Save button on the embedded form to clear the embedded form fields after saving a new or edited document
  • Hope that no one would try to view and create documents within the same page view

The Biggest Challenge

The biggest challenge I ran into was creating a new document with the embedded form after viewing or editing an existing document. No matter what I did, it would always update the previously-edited document with any changes that were made.

The Solution

Fortunately, I was able to solve that problem by scoping the data source to the request, so it stopped hanging onto the previous document and allowed for the creation of new documents. This was done via the scope property of the data source, found under All Properties > data > data > dominoDocument[0] > scope.

Managing the Data Source Dynamically

This method works, manipulating the data source directly makes it much simpler to implement and manage! With a few lines of code, you can replace the need for computed data source values, leaving all of the logic in the link that opens the form.

In my case, I’m attaching the data source to a panel on the page. Sven’s snippet shows how to attach the data source to the page itself.

This response from Sven to a question on Stack Overflow shows how you can clear all data sources and add a new one (to work around the same problem I was facing). Note: If you do that, be sure to set the variable name of the new data source the same as when you first bound fields to it, so all field bindings remain in tact.

I did some testing and found that I didn’t even need to remove and re-create the data source. I’ve been testing just updating the parameters of the data source and it seems to work well. One caveat I’ve seen so far is that if I try to open a document in edit mode, close it, then re-open in read mode before changing the documentId of the source to another document, it sticks with the first mode. If you have a case where you need to do that in succession, then maybe removing the data source and re-creating it altogether would do the trick.

The Code

Now, I have a ‘New’ button at the top and a repeat control with links to open and edit each document.

New Document

var ds = getComponent('panelName').getData()[0]; 
ds.setDocumentId(''); 
ds.setAction('createDocument'); 

Open Document (varRepeat is the repeat control variable)

var ds = getComponent('panelName').getData()[0]; 
ds.setDocumentId(varRepeat.getDocument().getUniversalID().toString()); 
ds.setAction('openDocument');

Edit Document (varRepeat is the repeat control variable)

 
var ds = getComponent('panelName').getData()[0]; 
ds.setDocumentId(varRepeat.getDocument().getUniversalID().toString()); 
ds.setAction('editDocument'); 

Two other things are required for this to work:

  1. The ignoreRequestParams property of the data source must be set to true, or the embedded form will pick up the id of the parent document from the URL. If you want to be sure it’s set properly, include this line: ds.setIgnoreRequestParams(true);
  2. Set the button or link to partially-refresh the panel that includes the embedded form and data source

This is much easier to maintain that all of the steps that the other method required.