Getting values from repeat control - xpages

I have a field inside a repeat control. Right now am using a viewScope in the onChange event to capture the field values inside the repeat control. Each time the field has to partial refreshes in order to get the value set in the scope variable.
The problem here is when the users set the focus outside the repeat control, the focus is not set until the partial refresh of the field is completed. Sometimes this partial refresh is too slow when user is accessing a remote domino server. Is there a effective way to capture the values inside the repeat control when the form is submitted?
The idea is to create fields dynamically when user click on the add button. The problem happen when you move the focus from the field inside the repeat control to the field outside the repeat control. The focus is not set, until the partial refresh of field inside the repeat control is completed. You may not occur this scenario, if the server is running locally on your machine. The below code shows the usage of repeat control to create fields dynamically
<xp:button value="Add Objects" id="addNavObj">
<xp:eventHandler event="onclick" submit="true"
refreshId="objLine" refreshMode="partial" id="eventHandler24">
<xp:this.action><![CDATA[#{javascript:viewScope.rowItems=viewScope.rowItems+1;getComponent("navObjRep").setValue(parseInt(viewScope.rowItems));}]]></xp:this.action>
</xp:eventHandler>
</xp:button>
<xp:repeat rows="30" var="rowData" indexVar="rowIndex"
repeatControls="false" first="0" value="#{javascript:viewScope.rowItems}"
id="navObjRep" style="width:800.0px">
<xp:panel style="width:800.0px" id="objLine">
<xp:table style="width:800.0px">
<xp:tr>
<xp:td style="width:245.0px">
<xp:inputText id="objType" style="width:130.0px">
<xp:typeAhead mode="full" minChars="1" ignoreCase="true"
id="typeAhead4" rendered="false">
</xp:typeAhead>
</xp:inputText>
</xp:td>
<xp:td style="width:46.0px">
<xp:inputText id="objCode">
<xp:eventHandler event="onchange" submit="true"
refreshMode="partial" refreshId="objCode" id="eventHandler3">
<xp:this.action><![CDATA[#{javascript:viewScope['objCode'+rowIndex] = getComponent("objCode").getValue()}]]></xp:this.action>
</xp:eventHandler>
</xp:inputText>
</xp:td>
<xp:td style="width:300.0px">
<xp:inputTextarea id="objDesc" style="height:40.0px;width:200.0px">
<xp:eventHandler event="onclick" submit="false" id="eventHandler40"></xp:eventHandler>
<xp:eventHandler event="onchange" submit="true"
refreshMode="partial" refreshId="objDesc" id="eventHandler4">
<xp:this.action><![CDATA[#{javascript:viewScope['objDesc'+rowIndex] = getComponent("objDesc").getValue()}]]></xp:this.action>
</xp:eventHandler>
</xp:inputTextarea>
</xp:td>
</xp:tr>
</xp:table>
</xp:panel>
</xp:repeat>

Don't use the onChange event of an edit box for a partial refresh - you create an experience night mare. Excercise 23 has all you need.

Its just a simple, example for a repeat control with a variable number of input and computed Fields.Hope it helps you to solve your problem.
<xp:this.beforePageLoad><![CDATA[#{javascript:var languages:java.util.Vector = #Explode("de,en,pl",",");
viewScope.put("allLanguages",languages);
viewScope.put("selectedLanguages", languages)}]]>
</xp:this.beforePageLoad>
<xp:checkBoxGroup id="checkBoxGroup1" value="#{viewScope.selectedLanguages}">
<xp:this.defaultValue><![CDATA[#{javascript:return viewScope.get( "allLanguages" );}]]></xp:this.defaultValue>
<xp:eventHandler event="onchange" submit="true" refreshMode="complete">
<xp:this.action><![CDATA[#{javascript:// full update //partial update}]]></xp:this.action>
</xp:eventHandler>
<xp:selectItems>
<xp:this.value><![CDATA[#{javascript:return viewScope.get( "allLanguages" );}]]></xp:this.value>
</xp:selectItems>
</xp:checkBoxGroup>
<xp:repeat id="repeat1" rows="30" var="varcollection" repeatControls="true">
<xp:this.value><![CDATA[#{javascript:return viewScope.get( "allLanguages" );}]]></xp:this.value>
<xp:span>
<xp:this.rendered><![CDATA[#{javascript:var vec:java.util.Vector = viewScope.get( "selectedLanguages" );
return #IsMember(varcollection,vec);
}]]></xp:this.rendered>
<xp:label id="label1">
<xp:this.value><![CDATA[#{javascript:return varcollection + ": ";}]]></xp:this.value>
</xp:label>
<xp:inputText id="inputText1" loaded="true">
<xp:this.value><![CDATA[${javascript:var fieldName = "Help_" + varcollection;
return '#{viewScope.' + fieldName + '}';}]]></xp:this.value>
<xp:eventHandler event="onchange" submit="true"
refreshMode="partial" refreshId="computedField1">
</xp:eventHandler></xp:inputText>
  <xp:text escape="true" id="computedField4"><xp:this.value><![CDATA[#{javascript:var fieldName = "Help_" + varcollection;
return '#{viewScope.' + fieldName + '}';}]]></xp:this.value></xp:text>  
<xp:text escape="true" id="computedField1">
<xp:this.value><![CDATA[${javascript:var fieldName = "Help_" + varcollection;
return '#{viewScope.' + fieldName + '}';
}]]></xp:this.value>
</xp:text>
<xp:br></xp:br>
</xp:span>
</xp:repeat> <xp:br></xp:br>
<xp:button value="Submit" id="button1">
<xp:eventHandler event="onclick" submit="true" refreshMode="complete" immediate="false" save="true"></xp:eventHandler></xp:button>
<xp:br></xp:br>
<xp:br></xp:br>
<xp:text escape="true" id="computedField3"><xp:this.value><![CDATA[#{javascript:return "value1 = " +viewScope["Help_de"] +
"value2 = " +viewScope["Help_en"] +
"value3 = " +viewScope["Help_pl"]}]]></xp:this.value></xp:text>
The last computet field: computetdField3 will get the values 'onSubmit' and the others onChange.

I strugled for a few hours with about the same problem.
I have a repeat build up from different views and even do some consolidation on the result to show a nice input matrix of 3 field per row.
I want to create new documents for every line that has fields filled in in the repeat.
Partial refresh is indeed a nightmare.
Finaly I ended up with client side script onfocus and onChange events to add my data into a hidden field on the page. I concatenate the 3 fields per row and put them in the hidden field seperated by a §.
When pressing the submit button I just get server side the value of that hidden field, #Explode("§") it and run trough the newly created array and create documents from them.

Related

using viewscope for repeat var does not update viewscope outside the repeat

This gets me every time.
I want to edit the viewScope components and then use the results elsewhere - but in this simple example the computed field does not update .... what is the best way to do this?
Thanks
<xp:this.beforePageLoad><![CDATA[#{javascript:viewScope.Test = [];
viewScope.Test.push("Hello");
viewScope.Test.push("Go");
viewScope.Test.push("Hello1");}]]></xp:this.beforePageLoad>
<xp:repeat id="repeat1" rows="30" value="#{viewScope.Test}"
var="row" indexVar="i">
<xp:inputText id="inputText1" value="#{row}">
<xp:eventHandler event="onchange" submit="true"
refreshMode="partial" refreshId="computedField1"></xp:eventHandler>
</xp:inputText>
</xp:repeat>
This is new data
<xp:text escape="true" id="computedField1"
value="#{viewScope.Test}">
</xp:text>
Fixed it by changing the value of inputText to "#{viewScope.Test[i]}"
<xp:this.beforePageLoad><![CDATA[#{javascript:
viewScope.Test = ["Test","Test1","Test2"];
}]]></xp:this.beforePageLoad>
<xp:repeat id="repeat1" rows="30" value="#{viewScope.Test}"
var="row" indexVar="i">
<xp:inputText id="inputText2" value="#{viewScope.Test[i]}">
<xp:eventHandler event="onchange" submit="true"
refreshMode="partial" refreshId="computedField1">
</xp:eventHandler></xp:inputText>
</xp:repeat>
<xp:br></xp:br>This is new data
<xp:text escape="true" id="computedField1" value="#{viewScope.Test}"></xp:text>

How to do a partial refresh of multiple items in Xpages correctly

I have read many of the blog posts on doing a partial refresh on more than one element, but I cannot seem to get it to work.
I made a "toy" example, an Xpage with two fields and one button. Both fields are bound to a sessionScope counter. The button increments the counter and does a partial refresh on the containing panel.
I want to do a partial refresh on the first field, which is not in the panel [in my real Xpage the two fields are very far apart on the form.
Tried many different things to get this to work, but none worked. Is it even possible to do this?
<?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"
style="background-position:center left"
xmlns:on="http://www.openntf.org/domino/xsp" viewState="nostate"
xmlns:debug="http://www.openntf.org/xsp/debugtoolbar">
First Var<br></br>
<xp:text escape="true" id="computedField1" value="#{sessionScope.number}">
</xp:text>
<br></br>
<xp:br></xp:br>
<br></br>
Second Var<xp:panel id="pnl1">
<xp:text escape="true" id="computedField2" value="#{sessionScope.number}">
</xp:text>
<br></br>
<br></br>
<xp:button value="Label" id="button1">
<xp:eventHandler event="onclick" submit="true"
refreshMode="partial" refreshId="pnl1" execMode="partial"
execId="pnl1">
<xp:this.action><![CDATA[#{javascript:var t = sessionScope.number + 1;
sessionScope.number = t;}]]></xp:this.action>
</xp:eventHandler>
</xp:button>
</xp:panel>
</xp:view>
Read Knut's link and got this to work. I made a change to the event handler of the button and it worked. Here is the code:
<xp:eventHandler event="onclick" submit="true"
refreshMode="partial" refreshId="pnl1" execMode="partial"
execId="pnl1">
<xp:this.action><![CDATA[#{javascript:var t = sessionScope.number + 1;
sessionScope.number = t;}]]></xp:this.action>
<xp:this.onComplete><![CDATA[XSP.partialRefreshPost("#{id:computedField1}");]]></xp:this.onComplete>
</xp:eventHandler>
Use XSP.partialRefreshPost(): http://avatar.red-pill.mobi/tim/blog.nsf/d6plinks/TTRY-84B6VP

How to Save Values in Documents Edited In-line On Repeat Control

I have a repeat control on an xPage with a text field displayed directly in edit mode. When a user changes the value in the field, I need them to be able to either:
Select an icon directly beside the field to save the value in the document.
Make changes to this field in more than one document and click a button to save all of these changes to the appropriate documents saved simultaneously.
What I have so far is a method of capturing the unids of the documents whose editable field has been updated.
I cannot get either of these saves to work. I have listed below the portion of the code that controls these areas.
Here's the save all and sessionScope information
<xp:panel id="InlineEditContainer" xp:key="facetMiddle" style="width:100%">
<xp:this.data>
<xp:dominoView var="view1" viewName="vwMetricsByAssigned">
<xp:this.postOpenView><![CDATA[#{javascript:var myList = new java.util.ArrayList();
sessionScope.put("myList", myList);}]]></xp:this.postOpenView></xp:dominoView>
</xp:this.data>
<xp:button value="Submit All" id="button1">
<xp:eventHandler event= <"onclick" submit="true" refreshMode="complete">
<xp:this.action><![CDATA[#{javascript:// Getting list of unids from docs which have been updated, and saving those docs
var db:NotesDatabase
if(sessionScope.myList == null){
return;
}else{
for (var s in sessionScope.myList){
var doc:NotesDocument = (db ? db.getDocumentByUNID(s) : database.getDocumentByUNID(s));
if (doc && doc.isValid()) {
doc.save();
}
}
}}]]></xp:this.action>
</xp:eventHandler>
</xp:button>
<xp:br></xp:br>
<xp:repeat id="repeat1" rows="30" value="#{sessionScope.myList}" var="listData">
<xp:text escape="true" id="computedField6"><xp:this.value><![CDATA[#{javascript:listData + " , "}]]></xp:this.value></xp:text></xp:repeat>
<xp:br></xp:br>
Here's all the repeat data
<xp:repeat id="repeat2" rows="20" var="FColl" indexVar="idx" value="#{javascript:view1}">
<xp:panel id="InlineEditContainer2">
<xp:this.data>
<xp:dominoDocument var="document1" formName="frmMetricData" action="editDocument" documentId="# {javascript:FColl.getNoteID();}" >
</xp:dominoDocument>
</xp:this.data>
<xp:tr>
<xp:td id="td1">
<xp:text escape="true" id="computedField3">
<xp:this.value> <![CDATA[#javascript:FColl.getDocument().getItemValueString("BusinessUnit")}]]>
</xp:this.value>
</xp:text>
</xp:td>
<xp:td id="td2">
<xp:link escape="true" id="link1" value="/MetricData.xsp">
<xp:this.text><![CDATA[#{javascript:FColl.getDocument().getItemValueString("MetricName")}]]> </xp:this.text>
<xp:eventHandler event="onclick" submit="true" refreshMode="norefresh" immediate="true">
<xp:this.action>
<xp:openPage name="/MetricData.xsp" target="editDocument" documentId="#{javascript:return FColl.getNoteID();}" />
</xp:this.action></xp:eventHandler>
</xp:link>
</xp:td>
<xp:td id="td3">
<xp:inputText id="EditBox3" value="#{document1.Actual}" tabindex="1">
<xp:this.defaultValue><![CDATA[# {javascript:FColl.getDocument().getItemValueString("Actual")}]]></xp:this.defaultValue>
<xp:this.converter>
<xp:convertNumber type="number" integerOnly="true" />
</xp:this.converter>
<xp:eventHandler event="onchange" submit="true" refreshMode="partial" refreshId="repeat1">
<xp:this.action><![CDATA[#{javascript:// get the universalID of the document
var keyCode = FColl.getDocument().getUniversalID();
// Create an Array
var myArray = sessionScope.get("myList");
//If it's not already in the Array then add it.
if (!myArray.contains(keyCode)) {
myArray.add(keyCode);
}}]]></xp:this.action>
</xp:eventHandler></xp:inputText>
<xp:span>
<xp:image url="/.ibmxspres/domino/oneuiv2/images/iconConfirmation16.png" id="image1">
<xp:eventHandler event="onclick" submit="true" refreshMode="complete">
<xp:this.action>
<xp:saveDocument var="document1" />
</xp:this.action>
</xp:eventHandler>
</xp:image>
</xp:span>
If anybody can give me any ideas to try, I would be very grateful.
Make it simple! There is a simple action "save". Comes in save and save all flavors. The later goes below the repeat and saves any changed document.

xpages search modulo inside a popup

With your help, I did create an Xpage with FTsearch & export into Excel features. The problem is the search being made based on multiple input fields ( let say > 10 ) the xpage is heavy texted + considering the fact there is also a view panel where I list the search results once the Search button is clicked.
This is the main reason I've tried to create ( after the link to Search&Export is clicked ) some pop-up dialog ( which contains an xpage, I guess ) and this pop-up dialog to contain all my input fields + the 2 buttons already created: search & export. So, after I press the Search button from my pop-up => the pop-up dialog is closed and the search results are displayed in the view panel, same thing for the Excel button: pop-up is closed and I open the excel file.
Currently, when I click the link to Search&Export I 'see' all the input panel for the search ( all the input fields + the two buttons ) and of course the view panel. It does work but I think a pop-up dialog will be more user-friendly and it will give more space for the xpage.
What I want to do: move all the inputs fields + the search and export to excel buttons into a dialog, which should appear when the link is clicked.
How to create a dialog which opens when a link is clicked and contains this panel below ( where all the input fields and button for the FTsearch are contained there )
My code for the panel which contains the input fields and the search & export button:
<xp:panel style="background-color:rgb(242,242,242);border-color:rgb(168,168,168);border-width:thin;border-style:solid">
<xp:table><xp:tr><xp:td><xp:label value="Din" id="label3" style="font-size:8pt;font-family:Verdana;color:rgb(128,0,0)">
</xp:label></xp:td>
<xp:td><xp:inputText id="inputText1" value="#{sessionScope.searchDate1}">
// some extra code
</xp:label></xp:td>
<xp:td></xp:td>
<xp:td>
<xp:inputText id="inputText2" value="#{sessionScope.searchDate2}">
// some extra code
</xp:inputText></xp:td>
</xp:tr>
<xp:tr>
<xp:td>
<xp:label value="Author" id="label1"
style="font-size:8pt;font-family:Verdana;color:rgb(128,0,0)">
</xp:label>
</xp:td>
<xp:td>
<xp:inputText id="searchAutor"
value="#{sessionScope.searchAutor}">
</xp:inputText>
</xp:td>
<xp:td></xp:td>
<xp:td></xp:td>
</xp:tr>
<xp:tr>
<xp:td style="font-family:Verdana;font-size:8pt">
<xp:label id="label2" value="Titlu carte"
style="color:rgb(128,0,0);font-size:8pt;font-family:Verdana">
</xp:label>
</xp:td>
<xp:td>
<xp:inputText id="searchTitlu"
value="#{sessionScope.searchTitlu}">
</xp:inputText>
</xp:td>
<xp:td></xp:td>
<xp:td></xp:td>
</xp:tr>
<xp:tr>
<xp:td>
<xp:button value="Search" id="button6"
styleClass="lotusFormButton">
<xp:eventHandler event="onclick" submit="true"
refreshMode="complete" immediate="false" save="true"
id="eventHandler1">
</xp:eventHandler>
</xp:button>
</xp:td>
<xp:td>
<xp:text escape="true" id="computedField1"
rendered="false">
<xp:this.value><![CDATA[#{javascript:return "Query = " + sessionScope.queryString}]]></xp:this.value>
</xp:text>
</xp:td>
<xp:td></xp:td>
<xp:td>
<xp:button value="Export" id="button1"
styleClass="lotusFormButton" style="float:right;">
<xp:eventHandler event="onclick" submit="true"
refreshMode="complete" immediate="false" save="true"
id="eventHandler2">
<xp:this.action>
<xp:openPage
name="/export_hidden.xsp">
</xp:openPage>
</xp:this.action>
</xp:eventHandler>
</xp:button></xp:td>
</xp:tr>
</xp:table></xp:panel>
I appreciate your time.
Here's an example of a dialog where you can add your fields to:
<xe:dialog id="exampleDialog" title="Example dialog">
<xp:div styleClass="lotusDialogContent">
<!-- Add your table here -->
</xp:div>
<div class="lotusDialogFooter">
<!--
add your buttons here
-->
<!-- example cancel link -->
<xp:link id="link1" text="Cancel" styleClass="lotusAction">
<xp:eventHandler event="onclick" submit="false">
<xp:this.script><![CDATA[XSP.closeDialog('#{id:exampleDialog}')]]></xp:this.script>
</xp:eventHandler>
</xp:link>
</div>
</xe:dialog>
You open the dialog using server-side JS like this:
getComponent("exampleDialog").show();
Or like this using client-side JS:
XSP.openDialog("#{id:exampleDialog}")
You can also style the content and button bar area entirely using extension library. Your dialog would then look like this:
<xe:dialog id="exampleDialog">
<xe:dialogContent id="dialogContent1">
<!-- content here -->
</xe:dialogContent>
<xe:dialogButtonBar id="dialogButtonBar1">
<!-- buttons here -->
</xe:dialogButtonBar>
</xe:dialog>
Here's an example of a button that you can use inside the dialog to close the dialog and refresh the viewpanel on the same XPage (assuming the viewpanel is called "viewpanel1"):
<xp:button value="Search" id="searchButton">
<xp:eventHandler event="onclick" submit="true" refreshMode="partial" immediate="false" save="false" refreshId="viewpanel1">
<xp:this.action><![CDATA[#{javascript:
getComponent('exampleDialog').hide()
}]]></xp:this.action>
</xp:eventHandler>
</xp:button>
You can use XSP.addOnLoad() to open the dialog once the page is loaded. Add this to your XPage:
<xp:scriptBlock id="scriptBlock1">
<xp:this.value><![CDATA[
XSP.addOnLoad(function(){
XSP.openDialog("#{id:exampleDialog}")
});
]]></xp:this.value>
</xp:scriptBlock>

dynamic combobox does not update it's binding scopevar when it's items get updated

I ran in some troubles with a combobox. Here is a copy/paste example code to demonstrate my problem.
<xp:this.beforeRenderResponse><![CDATA[#{javascript://
viewScope.value1 = "document.getItemValueString('value1')" + viewScope.document;
viewScope.value2 = "document.getItemValueString('value2')" + viewScope.document;}]]>
</xp:this.beforeRenderResponse>
<xp:button
value="change document"
id="button1">
<xp:eventHandler
event="onclick"
submit="true"
refreshMode="complete">
<xp:this.action><![CDATA[#{javascript: viewScope.document = new Date().getMilliseconds()//}]]></xp:this.action>
</xp:eventHandler>
</xp:button>
<br></br>
<xp:comboBox id="comboBox1" value="#{viewScope.value3}">
<xp:selectItems>
<xp:this.value><![CDATA[#{javascript:viewScope.value1;}]]></xp:this.value>
</xp:selectItems>
<xp:selectItems>
<xp:this.value><![CDATA[#{javascript:viewScope.value2;}]]></xp:this.value>
</xp:selectItems>
<xp:eventHandler
event="onchange" submit="true" refreshMode="complete">
<xp:this.action><![CDATA[#{javascript://}]]></xp:this.action>
</xp:eventHandler>
</xp:comboBox>
<br></br>
<xp:text escape="true" id="computedField1" value="#{viewScope.value1}"></xp:text>
<br></br>
<xp:text escape="true" id="computedField2" value="#{viewScope.value2}"></xp:text>
<br></br>
<xp:text escape="true" id="computedField3" value="#{viewScope.value3}"> </xp:text>
What did I try to accomplish: I have a combobox with two or more calculated selectItems. They depend on which document is currently selected. To demonstrate a switch of documents I use the button change document in this example. When a new document is selected the beforeRenderResponse event
gets the itemvalues from the document and puts them in a viewscope var. I have to separate the two values so I can't use a Array for them. That's all working so far but: If I select a value e.g. value2(timestamp1) and do a switch document the viewScope.value3 where the combobox is bound to did not update.
It displays the old value2 from the last document until I trigger its onChange event.
How can I force the comboBox to update its viewScope var with its selectItems?
Found a solution wich works at least for my copy/pase example:
<xp:this.beforeRenderResponse><![CDATA[#{javascript://
viewScope.value1 = "document.getItemValueString('value1')" + viewScope.document;
viewScope.value2 = "document.getItemValueString('value2')" + viewScope.document;
var list = new Array();
list.push(value1);
list.push(value2);
if(!#IsMember(viewScope.value3,list)){
viewScope.value3 = list[0];//list.pop();
}}]]>
</xp:this.beforeRenderResponse>
Now the viewScope.value3 gets changed to value1 if the documents is changed.

Resources