Xpage Custom Control / Repeaters Data Save Issue - xpages

This is a continuation of a previous question that I asked last week.
I have an XPage. On this XPage I have a repeater. In this repeater, I have a custom control that I am using to display the contents of its own datasource - a NotesXspDocument. This control is repeated 5 to 10 times, maybe up to 15 times. I do not want to make the user press on save for each and every repeated control, so I am using the submit button feature as described in the above linked question.
When the user presses the submit button, I am using the querySaveDocument and the postSaveDocument actions on the events tab (I also tried the properties with the same name in the Data tab with the same result). My issue is the following:
The validation is executed one control instance after another until the validation fails immediately saving the datasource before moving on to the next instance. When a NEW document is saved, it seems like the XspDocument is gone and the fields are emptied. I have checked, and I have set the datasource scope to view, as this behavior somehow resembles requestScope. As soon as I reload the page, the information is correctly presented.
I could use "context.reloadPage()" to just get the updated information, but this has the nasty side effect of removing all unsaved information (for example if validation failed on the xth line). How might I best go about solving/troubleshooting this issue? What should I be paying attention to? Has anyone else seen such a behavior?
I would love to call a validate function on all rows from the Containing XPage and then if all rows succeeded, then call the saveDataSources function. Any help is greatly appreciated!

A simple button outside your repeat control will do. I created this example:
<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core">
<xp:repeat id="repeat1" rows="30" value="#{javascript:4}">
<xp:panel id="dataPanel" disableOutputTag="true">
<xp:this.data>
<xp:dominoDocument var="document1" formName="Demo2">
</xp:dominoDocument>
</xp:this.data>
<xp:table>
<xp:tr>
<xp:td>
<xp:label value="Subject!" id="subject_Label1" for="subject1">
</xp:label>
</xp:td>
<xp:td>
<xp:inputText value="#{document1.Subject}"
id="subject1" required="true">
<xp:this.validators>
<xp:validateRequired
message="Say something">
</xp:validateRequired>
<xp:validateLength minimum="5"
message="Say 5 characters or more">
</xp:validateLength>
</xp:this.validators>
</xp:inputText>
</xp:td>
</xp:tr>
<xp:tr>
<xp:td>
<xp:label value="Color!" id="color_Label1" for="color1">
</xp:label>
</xp:td>
<xp:td>
<xp:comboBox value="#{document1.Color}"
id="color1" defaultValue="red">
<xp:this.validators>
<xp:validateExpression
message="We don't like red">
<xp:this.expression><![CDATA[#{javascript:value != "red"}]]></xp:this.expression>
</xp:validateExpression>
</xp:this.validators>
<xp:selectItem itemLabel="red"></xp:selectItem>
<xp:selectItem itemLabel="yellow"></xp:selectItem>
<xp:selectItem itemLabel="green"></xp:selectItem>
<xp:selectItem itemLabel="blue"></xp:selectItem>
<xp:selectItem itemLabel="white"></xp:selectItem>
<xp:selectItem itemLabel="black"></xp:selectItem>
</xp:comboBox>
</xp:td>
</xp:tr>
</xp:table>
</xp:panel>
</xp:repeat>
<xp:messages layout="table" style="color:red" id="messages1">
</xp:messages>
<xp:button value="Save?" id="button1">
<xp:eventHandler event="onclick" submit="true"
refreshMode="complete" immediate="false" save="true"></xp:eventHandler>
</xp:button>
</xp:view>
It will not save any of the data unless all validations are satisfied and it will not remove any entered data either. Don't get into the way what XPages does automatically (you also don't brush a cat against her fur). Your validation should happen in the validator and let the data source be saved by the button. As you see: no Query/Post event code is needed here.

I really don't get what you're trying to do so I'll just comment on a piece.
If you want data to survive a context.reloadPage() I think you would need to bind your controls to sessionScope. ViewScope is probably wiped out during the reload but sessionScope should still be available.
Good Luck!

Related

XPages: can a Depositor modify a document?

I created a user Guest with Depositor rights. He can also Read and Write Public Documents. The test document I created has a field $PublicAccess with value "1". To open the document in the Guest XPage using a browser, I use this URL:
https:://domain/database.nsf/Guest.xsp?documentId=E696&action=editDocument
The page opens, the Summary field is filled from the document with ID=E696, but it stays read-only. If I add a 2nd dominoDocument that creates a new document, that field is editable, and clicking the Save button will save the data.
Is it possible to allow a Depositor to modify a Public document?
Here's my simple XPage:
<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core">
<xp:this.data>
<xp:dominoDocument var="document1" formName="ABC"></xp:dominoDocument>
<xp:dominoDocument var="document2" formName="XYZ" ignoreRequestParams="true"></xp:dominoDocument>
</xp:this.data>
Summary
<xp:br></xp:br>
<xp:inputText id="inputText1" value="#{document1.Summary}"></xp:inputText>
<xp:br></xp:br>
Code
<xp:br></xp:br>
<xp:inputText id="inputText2" value="#{document2.Code}"></xp:inputText>
<xp:br></xp:br>
<xp:br></xp:br>
<xp:button value="Save" id="button1">
<xp:eventHandler event="onclick" submit="true" refreshMode="complete">
<xp:this.action>
<xp:saveDocument var="document2"></xp:saveDocument>
</xp:this.action>
</xp:eventHandler>
</xp:button>
</xp:view>
What I found out is that the presence of any valid non-empty Authors field (e.g. with a name or a role) will block edit access for Anonymous or a Depositor. My "solution" is to change the Authors property, by using setAuthors(false) on every Authors field.

Accessing value of Editable field in repeat control

How can I access the value of an computed field in a repeat control?
In the example below, I have cfT5Budget in a repeat control. I want to be able to access the value of each of the cfT5Budget control (repeat1:0:cfT5Budget, repeat1:1:cfT5Budget, etc..)
I want to be able to have that same value replicated into my second repeat control. I will be doing other stuff in the second control but for this example, it's just a simple code.
<xp:table>
<xp:repeat id="repeat1" var="rowItem1" indexVar="indexVar1">
<xp:this.value><![CDATA[#{javascript:['a', 'b', 'c']}]]></xp:this.value>
<xp:tr>
<xp:td>
<xp:text escape="true" id="cfT5Budget" value="#{javascript:5 + indexVar1}">
</xp:text>
</xp:td>
</xp:tr>
</xp:repeat>
</xp:table>
<xp:table>
<xp:repeat id="repeat2" var="rowItem2" indexVar="indexVar2">
<xp:this.value><![CDATA[#{javascript:getComponent('repeat1').getValue()}]]></xp:this.value>
<xp:tr>
<xp:td>
<xp:text escape="true" id="cfT5Budget2" value="#{javascript:VALUE OF cfT5Budget GOES HERE}">
</xp:text>
</xp:td>
</xp:tr>
</xp:repeat>
</xp:table>
Thank you in advance :)
The short answer: use data binding.
The long answer:
In MVC your code should not interact with the View (a.k.a the fields), but rather the model (a.k.a the data). So instead of computing the values like in your example, you bind them using the variable name provided in the repeat.
You interact with that collection (Array) not the fields. This makes code easier and more robust since the code doesn’t need to care what UI element is used.
Hope that helps

Time Zone issue in xpages time control

I hope you guys are doing good. I am using date and time control on front end for selection of Time from date and time control and only time is visible at front end. My users are using different timezone.
(UTC +09) Osaka, Singapore, Tokyo
(UTC +05) Tashkant
Now data stored in time field is different in binding field. How can I override field data using SSJS to keep all users in single timezone.
e.g. i want to using UTC +05 for all users having different zones.
Kindly let me know if you require any clarification about my question.
Thanks,
Qaiser
According to this info you can automaticaly convert date/time field to specific time zone natively.
Try this example:
<?xml version="1.0" encoding="UTF-8"?>
<xp:view
xmlns:xp="http://www.ibm.com/xsp/core">
<xp:this.data>
<xp:dominoDocument
var="document1"
formName="FRM">
</xp:dominoDocument>
</xp:this.data>
<xp:label
value="UTC Tashkent:"
id="label1"
for="computedField1">
</xp:label>
<xp:inputText
id="inputText1"
value="#{document1.utc5}"
defaultValue="#{javascript:#Now()}">
<xp:this.converter>
<xp:convertDateTime
timeZone="Asia/Tashkent"
type="time"></xp:convertDateTime>
</xp:this.converter>
<xp:dateTimeHelper></xp:dateTimeHelper>
<xp:eventHandler
event="onclick"
submit="true"
refreshMode="complete">
</xp:eventHandler>
</xp:inputText>
 Your UTC:  <xp:text
escape="true"
id="computedField1"
value="#{document1.utc5}">
<xp:this.converter>
<xp:convertDateTime
type="time"></xp:convertDateTime>
</xp:this.converter>
</xp:text>
<xp:br></xp:br>
<xp:button
value="Save"
id="button1">
<xp:eventHandler
event="onclick"
submit="true"
refreshMode="complete">
<xp:this.action>
<xp:saveDocument
var="document1"></xp:saveDocument>
</xp:this.action>
</xp:eventHandler>
</xp:button>
</xp:view>
The page forces edit box to be shown in Tashkent time zone, regardless of browser's settings. Be aware, that stored value may be different, if server's time zone is different from the forced one.

REST services and Xpages Server side validation

I am new to extension library REST services and xpages, I need to find out a way where I can validate user input data with servers data, to avoid server round trip, I am planning to use REST services.
I tried using something below but no luck, can any one please correct me where the below code is failing.
<?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"
xmlns:xc="http://www.ibm.com/xsp/custom">
<xp:this.data>
<xp:dominoDocument var="document1" formName="NavConfig"></xp:dominoDocument>
</xp:this.data>
<xe:restService id="restService1">
<xe:this.service>
<xe:documentJsonService compact="true"
formName="NavConfig">
<xe:this.querySaveDocument><![CDATA[#{javascript:var cmp=getComponent('menuItem1').getValue();
if (cmp=""){
getComponent('msg').setValue("Validation Failed")
}}]]></xe:this.querySaveDocument>
</xe:documentJsonService>
</xe:this.service>
</xe:restService>
<xp:br></xp:br>
<xp:br></xp:br>
<xp:text escape="true" id="msg"></xp:text>
<xp:panel style="margin-left:20.0px;margin-top:20.0px">
<xp:table>
<xp:tr>
<xp:td>
<xp:label value="Menu item:" id="menuItem_Label1"
for="menuItem1">
</xp:label>
</xp:td>
<xp:td>
<xp:inputText value="#{document1.MenuItem}"
id="menuItem1">
</xp:inputText>
</xp:td>
</xp:tr>
<xp:tr>
<xp:td>
<xp:label value="Link address:"
id="linkAddress_Label1" for="linkAddress1">
</xp:label>
</xp:td>
<xp:td>
<xp:inputText value="#{document1.linkAddress}"
id="linkAddress1">
</xp:inputText>
</xp:td>
</xp:tr>
</xp:table></xp:panel>
<xp:panel style="margin-top:20.0px;margin-left:20.0px">
<xp:button value="Save" id="button2"><xp:eventHandler event="onclick" submit="true" refreshMode="complete">
<xp:this.action>
<xp:save></xp:save>
</xp:this.action></xp:eventHandler></xp:button></xp:panel>
</xp:view>
REST by nature is a "dumb" API. I would rather say: elegant in its simplicity. You GET data from a server and you PUT/POST it back or DELETE it. So every time you talk to REST, you have a server round trip - that is REST how it is build.
In XPages when your client (JavaScript) is requesting data via REST, that service doesn't interact with any of the components on the page, so checking a menu or setting a component's text has no impact on the REST call.
When you want to do client side validation you need to implement that in client side script otherwise you do have a server round trip (which might not be that bad actually).
I would, to be most flexible, use a custom REST service (also provided by the rest control) to create your own JSON that contains only
the items you actually need but adds info for your local validation code like {'requiredFields' : [{'name' : 'subject', 'message' : 'hey sorry, I need a subject to process this'}, {...}]} and a status reply when you POST data back.
Check the sample database and the book.

Xpages - Conflict is created everytime a document is saved

I have a xpage, with multiple tabs. First tab contains a panel, whose content are editable only when isNewNote() is true. So I computed readonly attribute for the panel.
But everytime I save the document, it is creating a new conflict document.
At the sametime,if I uncheck read-only property, it is saving properly without any conflict.
Can anybody help me to solve this issue?
CODE - Xpage
<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core">
<xp:this.data>
<xp:dominoDocument var="document1"
formName="frmOnboardingRequest">
</xp:dominoDocument>
</xp:this.data>
<xp:panel>
<xp:this.readonly><![CDATA[#{javascript:if(document1.isNewNote()){
return false;
}else{
return true;
}}]]></xp:this.readonly>
<xp:table>
<xp:tr>
<xp:td>
<xp:label value="O n_ e d_ form completed by:"
id="oN_ED_FormCompletedBy_Label1" for="oN_ED_FormCompletedBy1">
</xp:label>
</xp:td>
<xp:td>
<xp:inputText
value="#{document1.ON_ED_EmployeeName}"
id="oN_ED_FormCompletedBy1">
</xp:inputText>
</xp:td>
</xp:tr>
</xp:table></xp:panel>
<xp:button value="Submit" id="button1"><xp:eventHandler event="onclick" submit="true" refreshMode="complete" immediate="false" save="true"></xp:eventHandler></xp:button></xp:view>
Check for multiple datasources pointing to the same document.
Some posts before with the same problem
xpage creates save conflict on save/submit
Multiple data sources in XPages
Lotus Notes: Replication conflict caused by agent and user running on the document at same time
=================================================
Edit
I had to change the button code to this to get the same problem
<xp:button value="Submit" id="button1"><xp:eventHandler event="onclick" refreshMode="complete" submit="true">
<xp:this.action>
<xp:saveDocument></xp:saveDocument>
</xp:this.action></xp:eventHandler></xp:button>
After some more testing, try this.
Add this field to the end of the xpage
<xp:inputText id="inputText1"
value="#{document1.temp}"
style="visibility:hidden;display:none">
</xp:inputText>
Then no conflicts are created.
Strange indeed - but also not. Your data source is bound to the page and not to the panel. So if you want to set read mode only for that panel, consider to calculate the panel's datasource from the page's datasource:
<xp:panel>
<xp:this.data>
<xp:dominoDocument var="document1" action="openDocument"></xp:dominoDocument>
</xp:this.data>
</xp:panel>
Of course you have to calculate the document mode and the docid instead of using the readonly property.
In addition to the other suggestions, when working with tabbed tables you will want to follow this blog post carefully. I have been through similar issues on a previous project and Tommy Valand's redirectToCurrentDocument() fixed them.
http://dontpanic82.blogspot.com/2010/06/xpages-avoid-saving-duplicate-documents.html

Resources