Posts Tagged With: requestScope

Exploring requestScope, viewScope and multiple source documents in #xpages

As I’ve mentioned previously, much of my current work revolves around one database used to allow organizations to request grants for one of our projects. In doing so, when they open the XPage to request a grant, there are four separate attachment documents as source documents to the XPage, as well as the main document and a contact document. One of the issue I had with our initial roll out of the database was that users uploading their attachments ended up creating many rep/save conflicts and getting every attachments loaded on every source document except the contact document. I had no idea why, but it was in production already and with less than 100 grant requests, I simply manually fixed all the rep/saves as they created them. Basically, using a hammer to repair ceramics.

The problematic code was, unbeknownst to me, my source declarations.

<xp:this.data>
	<xp:dominoDocument var="workplanDoc" formName="AttachAnnex" />
	<xp:dominoDocument var="projectBudgetDoc" formName="AttachAnnex" />
	<xp:dominoDocument var="budgetAssumptionsDoc"  formName="AttachAnnex" />
	<xp:dominoDocument var="performanceIndicatorsDoc" formName="AttachAnnex" />
</xp:this.data>

I knew something was wrong. I’d originally had those four source documents declared at the top of the XPage, but when I moved them onto a custom control, it seemed to me that I’d resolved them problem. Unfortunately, I think it was only working some of the time (new grant requests, which had no documentId= in the URL, I suspect), if at all.

So, I wondered and I searched. Then, the daily compilation of Lotus Notes questions on Stack Overflow came through. The first item was labelled “XPage xe:Dialog box is edit previous create document”, which didn’t seem too interesting, but the snippet from the question raised my eyebrows, “I have a custom control that create a new document through ext-lib dialog box that work fine. However when the action is performed the second time it edit the document instead of creating a new …” I realized he was dealing with multiple data sources and having problems similar to mine. So, I opened the question and found great advice from Patrick Sawyer.

set ignoreRequestParams to true and then set the scope to request

Then, I followed links to his post to get more information, finding that even though I’d read Patrick’s question about multiple data sources and commented on it, no less, that I had no recollection of that solution (provided by Tim Tripcony!) So, I changed my code.

<xp:this.data>
	<xp:dominoDocument var="workplanDoc" formName="AttachAnnex"
	 ignoreRequestParams="true" scope="view" />
	<xp:dominoDocument var="projectBudgetDoc" formName="AttachAnnex"
	 ignoreRequestParams="true" scope="view" />
	<xp:dominoDocument var="budgetAssumptionsDoc" formName="AttachAnnex"
	 ignoreRequestParams="true" scope="view" />
	<xp:dominoDocument var="performanceIndicatorsDoc" formName="AttachAnnex"
	 ignoreRequestParams="true" scope="view" />
</xp:this.data>

Tim explained the function of ignoreRequestParameters well in his answer to Patrick’s question:

If you omit the ignoreRequestParams attribute, then this data source doesn’t ignore the URL request parameters. Instead, it looks for parameters named databaseName, formName, documentId, and action. If any of these parameters are included in the URL, the value of each overrides what is defined on the data source.

So, what was happening was that if you started a grant request via the simple link, which was just the XPage URL, ending with “Application.XSP” then there were no parameters to worry about and the source documents might be created properly. However, if the users followed the link I’d emailed them, pointing to their specific document, with action=editDocument, and documentId= the UNID of their grant request, it would use those values and upload the attachment to main document, modify the form name to “AttachAnnex” and, with multiple uploads of many attachments, create a flurry of save conflicts. I’d go through and change form names on one of them and save the others, so they all got assigned new UNIDs.

Now, I tried both requestScope and viewScope, finally settling on viewScope. If I use requestScope, then each attachment upload creates a new Notes document with the attachment on it. If I use viewScope, then, for the span of that user session, each upload that the user does to that source document goes onto the same Notes document. If they come back and upload more documents in a separate session, it should create a new Notes document that would hold all of the attachments uploaded for that source document. So, with requestScope, if the user had 10 files to upload, some for each source document, they would be creating 10 Notes documents, regardless of whether they uploaded them in one sitting or several. With viewScope, if they uploaded 3 files to workplanDoc in one sitting, all 3 files would end up on 1 Notes document. Since I’d already worked out how to handle the linking to attachments for multi-attachment Notes documents, I chose viewScope, which keeps the attachments more organized.

Now, if I were to experiment, I expect that using sessionScope would create problems for any user who submits multiple grant requests, as it would use a four source documents for their entire session. This would put every workplan attachment onto one workplan Notes document that would end up associated only with the last grant request they edited. I could be even more foolish and grant the source documents applicationScope, which would put every attachment that any use uploaded into one of the four application-wide source documents, each time, associating it with a different grant request. Nightmarish!

I’d been wondering, and heard multiple speakers who discussed scope at various conferences say, “I’m not real sure why you’d use requestScope, but I know there are reasons.” Well, creating new source documents from an XPage that uses multiple source documents is just such a reason.

Advertisement
Categories: Xpages | Tags: , , , , , , | 1 Comment

Repeats and dynamic field bindings #xpages

In our purchase order module, we need to ask certain questions depending on the source selection method, competition type and total cost of the PO. These questions are likely to change over time and in between different instances of the database. So I have a view containing the questions, so that I can add questions dynamically to my XPage without needing to change the code.

To be honest, doing this in a regular Notes form would have required either putting every question on the form or putting a bunch of fields on the form for all the answer fields. Either method would be sloppy and wasteful. There could have been dozens of unnecessary answer fields hidden by hide-whens and constant revisions between various instances of the database leading to a configuration management/version control nightmare.

Doing it in a repeat control, with the source view filtered by values passed in an array, I can get dynamically selected questions with only the necessary fields being stored on the document.

In order to do this, I had to use all of my minimal XPages knowledge, ask several questions on Stack Overflow, re-read portions of Mastering Xpages and scour the help documentation. You, however, can simply follow my guidance and have this solution for your own.

The Question FormCompetition Question Form

I created a relatively simple Notes form, based on the ones supplied to us for keywords by Teamwork Solutions. The layout is clean and very readable, plus re-using it allows more consistency within our application. A number of the fields are used to determine when and where the question will display (Category, Competition type, Source selection method and Dollar ranges). The checkbox values are derived from keyword documents, to allow maximum flexibility. I’m allowing five field types for answers: Yes/No, Dialog Box, Text Box, Date and Date Range. I had tried Rich Text, but was having problems with losing the handle to the document when saving, and since it wasn’t really required in this implementation, dropped that for later review. Sometimes, the question has a related question to extract more details, so I allowed two questions to be placed on one question document to ensure they display together. Down at the bottom, I’ve got the fields to which the answer fields will be bound on the Notes document. One hazard to allowing the field to be named in this configuration document is that there might be duplicate use of a field name, by the risk level strikes me as low.

Setting up the Repeat

The way that I started to understand repeats was actually when I set up jQuery mobile access to some data after viewing Richard Sharpe’s webinar for TLCC on Building Your First Mobile Application Using XPages I was able to take the knowledge I acquired doing that and use it to link from one Requisition to many Purchase Orders as demonstrated on this blog.

The repeat itself is not that interesting, but, one of the technical tricks in the setup is. As I’ve started to learn XPages, I’ve gotten comfortable with variables stored in applicationScope (available to everyone), sessionScope (available throughout the current user’s session) and viewScope (available on the current page), but had no idea when one would ever use requestScope variables. It turns out that they can be very useful to us here, though we’re going to access them using a dataContext rather than labelling them as requestScope variables.

Since I want to take a value from each Question document to determine the field to bind to on the Purchase Order document, the syntax and re-use will be far easier if I can establish a variable for that field name used within each row of the repeat. This way, we can use Expression Language to refer to the field on the Purchase Order document, binding to it dynamically.

<xp:repeat id="repeat2" rows="30" var="rowData" style="width:700px" value="#{competitionQuestionView}">
    <xp:panel>
        <xp:this.dataContexts>
            <xp:dataContext var="fieldName">
                <xp:this.value><![CDATA[#{javascript:rowData.getColumnValue ("FieldName");}]]></xp:this.value>
            </xp:dataContext>
        </xp:this.dataContexts>
        <--- insert code here --->
    </xp:panel>
</xp:repeat>

First, we want to display our question, with the layout handled by a table. We just grab the column value and display it.

<xp:table>
    <xp:tr>
       <xp:td style="width:200.0px;">
          <xp:label id="label1">
             <xp:this.value><![CDATA[#{javascript:rowData.getColumnValue("Question");}]]></xp:this.value>
          </xp:label>
       </xp:td>

Then, in the right-hand cell, we have the various possible answer fields. Note that since only one is rendered (the rendering formulas being mutually exclusive), it doesn’t matter that we bind to the field multiple times, since only one binding actually appears on the page. Tim Tripcony guided me to this solution in his answer on Stack Overflow. By using array syntax, we bind to the field on the poDoc using the value of our requestScope variable, fieldName. Remember, as a requestScope variable, it is only “alive” for the duration of this data retrieval to create the field binding. The binding formula ends up being very simple: #{poDoc[fieldName]}

Here’s a portion of the answer fields to give you the flavor…

<xp:td>
   <xp:inputText id="inputText1" style="padding-top:2px;width:400px">
      <xp:this.rendered><![CDATA[#{javascript:rowData.getColumnValue("FieldType") == "Text Box"; }]]></xp:this.rendered>
      <xp:this.value><![CDATA[#{poDoc[fieldName]}]]></xp:this.value>
   </xp:inputText>
   <xp:comboBox id="comboBox1" style="padding-top:2px;">
      <xp:this.rendered><![CDATA[#{javascript:rowData.getColumnValue("FieldType") == "Dialog Box"; }]]></xp:this.rendered>
      <xp:selectItems>
         <xp:this.value><![CDATA[#{javascript:rowData.getColumnValue("DialogChoices")}]]></xp:this.value>
      </xp:selectItems>
      <xp:this.value><![CDATA[#{poDoc[fieldName]}]]></xp:this.value>
   </xp:comboBox>
   <xp:inputText id="inputText2" style="padding-top:2px;text-align:left">
      <xp:this.rendered><![CDATA[#{javascript:rowData.getColumnValue("FieldType") == "Date"; }]]></xp:this.rendered>
      <xp:dateTimeHelper id="dateTimeHelper1"></xp:dateTimeHelper>
      <xp:this.converter>
         <xp:convertDateTime type="date"></xp:convertDateTime>
      </xp:this.converter>
      <xp:this.value><![CDATA[#{poDoc[fieldName]}]]></xp:this.value>
   </xp:inputText>
   <xp:radioGroup id="radioGroup1" style="padding-top:2px;width:86.0px">
      <xp:this.rendered><![CDATA[#{javascript:rowData.getColumnValue("FieldType") == "Yes/No"; }]]></xp:this.rendered>
      <xp:selectItem itemLabel="Yes" itemValue="Yes"></xp:selectItem>
      <xp:selectItem itemLabel="No" itemValue="No"></xp:selectItem>
      <xp:this.value><![CDATA[#{poDoc[fieldName]}]]></xp:this.value>
   </xp:radioGroup>
</xp:td>

Since my Question document also allows for the addition of a comment question after the non-TextBox answers, I have another line on the XPage to display those (Note that the dataContext for the commentFieldName requestScope variable has to be added to that panel inside the repeat control as well).

<xp:tr id="commentRow">
   <xp:this.rendered><![CDATA[#{javascript:rowData.getColumnValue("DisplayComment") == "Yes"; }]]></xp:this.rendered>
   <xp:td style="border-bottom:grey solid 0px;padding-top:2px;">
      <xp:label id="label3">
         <xp:this.value><![CDATA[#{javascript:rowData.getColumnValue("CommentLabel");}]]></xp:this.value>
      </xp:label>
   </xp:td>
   <xp:td id="commentCell" style="border-bottom:grey solid 0px;padding-top:2px;">
      <xp:inputText id="inputText3">
         <xp:this.value><![CDATA[#{poDoc[commentFieldName]}]]></xp:this.value>
      </xp:inputText>
   </xp:td>
</xp:tr>

In my next blog post, we’ll look at how we filtered the view data source in order to only display the questions we want on a particular purchase order.

If you don’t already look at XPages questions on Stack Overflow, you really ought to, and if you haven’t been keeping up with TLCC’s webinars, check out the series.

Categories: Server-Side Javascript, Xpages | Tags: , , , , , , , | 1 Comment

Create a free website or blog at WordPress.com.

%d bloggers like this: