Xpages Repeat control inside repeat control - controls

I'm trying to bulid a dynamic table by the choice of comboBox1, as below:
the question is...how can I get the inputtext value? how can I bind the data
<xp:inputText id="inputText_${rptIndex}_${rptIndex1}"></xp:inputText>
I searched many articles on the web, still trapped. here is the whole code
<xp:repeat id="repeat2" rows="30"
indexVar="rptIndex" var="yhwzdetails">
<xp:this.value><![CDATA[#{javascript:if(getComponent("comboBox1").getValue()){
var subview = database.getView("vchsubstancebycategory");
var dcl = subview.getAllDocumentsByKey(getComponent("comboBox1").getValue());
if(dcl.getCount()> 0){return dcl;}}else{return 0}}]]></xp:this.value>
<xp:repeat id="repeat3" rows="30"
indexVar="rptIndex1" var="yhwzdetails1">
<xp:this.value><![CDATA[#{javascript:
var subview = database.getView("vchsubstancebycategory2nd");
var dcl = subview.getAllDocumentsByKey(getComponent("comboBox1").getValue() + yhwzdetails.getItemValueString("checkCategory"));
if(dcl.getCount()> 0){return dcl;}}]]></xp:this.value>
<xp:tr style="text-align:center">
<xp:td
style="width:25%;vertical-align:middle;background-color:#f3f3f3"
rendered="#{javascript:if(rptIndex1==0){return true}else{return false}}">
<xp:this.rowspan><![CDATA[#{javascript:
if(rptIndex1==0){
var subview = database.getView("vchsubstancebycategory2nd");
var dcl = subview.getAllDocumentsByKey(getComponent("comboBox1").getValue() + yhwzdetails.getItemValueString("checkCategory"));
return dcl.getCount();}
else{return 1}}]]>
</xp:this.rowspan>
<xp:text escape="true"
id="computedField3">
<xp:this.value><![CDATA[#{javascript:labellang(yhwzdetails.getItemValueString("checkCategory"))}]]></xp:this.value>
</xp:text>
</xp:td>
<xp:td
style="width:25%;background-color:#f3f3f3">
<xp:text escape="true"
id="computedField4">
<xp:this.value><![CDATA[#{javascript:labellang(yhwzdetails1.getItemValueString("checkName"))}]]></xp:this.value>
</xp:text>
</xp:td>
<xp:td style="width:25%">
<xp:inputText
id="inputText_${rptIndex}_${rptIndex1}">
</xp:inputText>
</xp:td>
<xp:td style="width:25%">
<xp:text escape="true"
id="computedField5" value="#{yhwzdetails1.PTNlimit}">
</xp:text>
</xp:td>
</xp:tr>
</xp:repeat>
</xp:repeat>
first I searched this articel:
https://xcellerant.net/2013/07/29/access-repeat-components-from-outside/
but I cant set the "Create controls at page creation" to true, so I can't use getComponent('inputText_' + rptIndex+'_' + rptIndex1)...trust me, I tried it....
then I searched these:
How to loop and get the values from all the components in a repeat when saving
Creating Global Array in in xPages using SSJS
xPages repeat control with scoped variable as data source
they all talk about using viewScope, and I DO think I can use it too, basiclly, I can store values in one 2D array like this
viewScope.test=[[100,200],[0,100,200,300],[....]]
but...how...and can I use it in my case? looking forwad your guys help, thanks

...I solved it by dynamic binding
<xp:inputText id="inputText_${rptIndex}_${rptIndex1}"
value="#{document1[yhwzdetails1.testppm]}">
</xp:inputText>

Related

Xpages filter and sort data in a repeat control?

I have a repeat control which displays a list of Attachments, which are saved as response documents to the current document. Right now I just see all the main docs and response docs in a list. How do I 1) Filter the view to only to include the response docs and not main docs? 2) Filter the view to only include responses to the current document?
I tried using the Filter by column value on the datasource, but I can't figure it out.
My Xpage datasources are "document1" document and "Requirements" view
<xp:dominoView var="Atts" viewName="Requirements">
</xp:dominoView>
<xp:repeat id="AttsContainer" rows="100"
var="Attachments" repeatControls="true" value="#{Atts}">
<xp:panel id="AttsPanel">
<xp:table style="width:100.0%;border-width:thin;border-color:rgb(0,0,0);border-style:solid">
<xp:tr>
<xp:td style="width:234.0px">
<xp:text escape="true"
id="computedField1" value="#{Attachments.AttName}">
</xp:text>
</xp:td>
<xp:td><xp:text escape="true" id="computedField2">
<xp:this.value><![CDATA[#{javascript:var doc:NotesDocument = Attachments.getDocument();
var sUNID = doc.getUniversalID();
sUNID}]]></xp:this.value>
</xp:text></xp:td>
<xp:td>
<xp:link escape="true"
id="link2">
<xp:this.text><![CDATA[#{javascript:Attachments.getColumnValue("Files")}]]></xp:this.text>
<xp:this.value><![CDATA[#{javascript:var doc:NotesDocument = Attachments.getDocument();
var sUNID = doc.getUniversalID();
ATT = Attachments.getColumnValue("Files");
"/bid.nsf/0/" + sUNID + "/$FILE/" + ATT}]]></xp:this.value></xp:link></xp:td>
</xp:tr>
</xp:table></xp:panel>
From the top of my head:
Create a view showing only the documents created with the response's form.
Disable the "show response documents in a hierarchy" property
Add a categorized first column with this formula: #Text($ref)
That gives you a view where all responses are categorized by their parents unid. You use that view in the data source and set the categoryFilter the the unid of the main document.

Xpages radio button validation by groupName?

I have radio buttons in a table with the same groupName.
Is there a relatively simple way to validate this field upon submitting the form without using CCJS?
<xp:td>
<xp:radio id="radio120" groupName="R_1" value="#{document1.R_1}" selectedValue="1"></xp:radio>
</xp:td>
<xp:td>
<xp:radio id="radio120" groupName="R_1" value="#{document1.R_1}" selectedValue="2"></xp:radio>
</xp:td>
With regular Radio Button Group controls, I use validateRequired with an errorMessage control to display a message.
<xp:radioGroup styleClass="A2" style="border:0px;" value="#{document1.Necktie}" layout="pageDirection" id="Necktie">
<xp:this.validators>
<xp:validateRequired message="REQUIRED!"></xp:validateRequired>
</xp:this.validators>
<xp:selectItem itemLabel="No" id="selectItem13"></xp:selectItem>
<xp:selectItem itemLabel="Yes" id="selectItem14"></xp:selectItem>
</xp:radioGroup>
<xp:message id="message10" for="Necktie"></xp:message>
Use the data source document1 on server side to find out if one of your radio buttons was selected.
Test for document1.getItemValueString("R_1"). If it is empty set an error message and return false. Otherwise save the document.
<xp:button value="Save" id="button1">
<xp:eventHandler event="onclick" submit="true"
refreshMode="complete">
<xp:this.action><![CDATA[#{javascript:
if (document1.getItemValueString("R_1") == "") {
facesContext.addMessage(null,
new javax.faces.application.FacesMessage("select a radio"));
return false;
}
document1.save();
}]]></xp:this.action>
</xp:eventHandler>
</xp:button>
<xp:messages id="messages1" />
Fair enough... In that case, outside of doing something with CSJS, I'm not too sure....
Not sure if this is going to help, but have a look at this post by Marky Roden:
https://xomino.com/2012/03/10/checking-xpages-radio-buttons-have-been-selected-with-jquery/
I haven't been doing any development work for 4/5 weeks as year end comes up so my brain isnt really working like it should.....

XPages. Hide column in DataTable

I'm trying to hide a column in the dataTable, but not working. Hiding only header. In example I try hide first column. Domino 9.0.1.
I was mistaken or is it a bug?
I know about the "display: none" for the column, but I have a lot of data, and not rendered column save my local performance
<xp:dataTable id="dataTable1" rows="30" var="item">
<xp:this.value><![CDATA[#{javascript:var collection = [];
for( var i = 0; i < 10; i++ ) {
var obj = {};
obj.name = "Name" + i;
obj.key = "Key" + i;
collection.push( obj );
}
return collection;}]]></xp:this.value>
<xp:column id="column1" rendered="false">
<xp:this.facets>
<xp:span xp:key="header">Name</xp:span>
</xp:this.facets>
<xp:text escape="true" id="computedField1"
value="#{item.name}">
</xp:text>
</xp:column>
<xp:column id="column2">
<xp:this.facets>
<xp:span xp:key="header">Key</xp:span>
</xp:this.facets>
<xp:text escape="true" id="computedField2" value="#{item.key}"></xp:text>
</xp:column>
</xp:dataTable>
I can confirm I get exactly the same behavior out of this. I agree that I would expect the entire column to not render, but that's apparently not its behavior. I've always viewed the xp:dataTable control as a slightly dressed up xp:repeat, but not with as much window dressing as an xp:viewPanel control and the Domino Designer wiki page on xp:dataTable isn't exactly helpful for any of the specifics and my Mastering XPages 2nd ed. also doesn't go too far into detail on xp:dataTable.
It's also worth noting that also setting the rendered property on your xp:text field still builds out the first cell in each row, regardless of the first <th> being suppressed. I'm guessing there's something in the way the xp:dataTable control builds out the HTML elements that's funky.
My recommendation would be to switch to an xp:repeat control, which will give you more control over the entire process. Adapting your code, it would go somewhat like this:
<xp:table>
<xp:tr>
<xp:td>Name</xp:td>
<xp:td>Key</xp:td>
</xp:tr>
<xp:repeat
id="repeat1"
rows="30"
var="item">
<xp:this.value><![CDATA[#{javascript:var collection = [];
for( var i = 0; i < 10; i++ ) {
var obj = {};
obj.name = "Name" + i;
obj.key = "Key" + i;
collection.push( obj );
}
return collection;}]]></xp:this.value>
<xp:tr>
<xp:td
rendered="false">
<xp:text
escape="true"
id="computedField1"
value="#{item.name}">
</xp:text>
</xp:td>
<xp:td>
<xp:text
escape="true"
id="computedField2"
value="#{item.key}">
</xp:text>
</xp:td>
</xp:tr>
</xp:repeat>
</xp:table>
Do note that to also set the rendering property of the cell being used as the header label (in place of a <th> it will render as a <td>), you'll need to manage that property visibility separately.

onChange event does not fire if there is field level validation

Below is the source of a very simplified XPage. It has a radio button group with two choices and an onchange event that sets viewScope.vsCompanies depending on the value selected. Then there is a field called Title that I have made Required. If I click on the radio button it changes from Contract to Lease and back but the onchange event never fires. Instead I get a warning that the Title is required. I only want the validation to fire when the document is being submitted so the onchange works. Do I have to make every one of the validations conditional on the submit being pressed, which seems like a lot of additional work. I could set a viewScope when the submit button is pressed and make it only required if that viewScope is true.
Sorry missed adding the code ps clientsideValidation is disabled
<xp:this.data>
<xp:dominoDocument var="CLDoc"
databaseName="Client Apps\LGI\XPages\LGIContracts-Leases.nsf"
formName="frmCL">
</xp:dominoDocument>
</xp:this.data>
<xp:this.properties>
<xp:parameter name="xsp.client.validation" value="false" />
</xp:this.properties>
<xp:br></xp:br>
<xp:messages id="messages1"></xp:messages>
<xp:radioGroup id="radioGroup1" value="#{CLDoc.Type}">
<xp:selectItem itemLabel="Contract"></xp:selectItem>
<xp:selectItem itemLabel="Lease"></xp:selectItem>
<xp:eventHandler event="onchange" submit="true"
refreshMode="partial" refreshId="comboBox1">
<xp:this.action><![CDATA[#{javascript:if (CLDoc.getValue("Type") == "Contract"){
viewScope.vsCompanies = ["A","B","C"];
return;
break;
}else{
viewScope.vsCompanies = ["X","Y","Z"];
return;
break;
}}]]></xp:this.action>
</xp:eventHandler>
</xp:radioGroup>
Company
<xp:br></xp:br>
<xp:comboBox id="comboBox1" value="#{CLDoc.Company}">
<xp:selectItems>
<xp:this.value><![CDATA[#{javascript:viewScope.vsCompanies}]]></xp:this.value>
</xp:selectItems>
</xp:comboBox>
<xp:br></xp:br>
Title
<xp:br></xp:br>
<xp:inputText id="inputText1" style="width:392.0px" value="#{CLDoc.Title}"
required="true">
<xp:this.validators>
<xp:validateRequired message="Title is required"></xp:validateRequired>
</xp:this.validators>
</xp:inputText>
I believe if you go to the Events you are able to disable validators for that event.
[edit]
I found a duplicate question here. xpages validation on field having onChange script
Looks like the event handler has the following parameter
disableValidators="true"

Need to know the way to stamp a field within a document collection which is in a repeat control

I have a repeat control which has its source as a notesdocumentcollection. Inside the repeat control I have a panel that has a datasource and the document id property of the datasource is set to the universal id of the a single document which in my case is the repeat control variable apprDoc (apprDoc.getUniversalID). Thus using the panel datasource I am trying to directly bind each field in the repeat control to the respective back end document. I have a submit button on click of which I need to post the values selected by the user into the backend document and also set some other fields which are not bound to the back end document. I need to get a handle to each document in the document collection in order to set a field value on the backend document. Can someone please suggest a way to do the same, or any other way to achieve the functionality which I am trying to achieve. Please find below the code for the same:
<xp:repeat id="repeat1" rows="30" var="apprDoc" indexVar="docIndex"
first="0">
<xp:this.value><![CDATA[#{javascript:// Look up the employee details view to get the employee appraisal details from the current database
var curDB:NotesDatabase = session.getCurrentDatabase();
var vwlkApprView:NotesView = curDB.getView("vwlkAllApprApper");
var collDocAppr:NotesDocumentCollection = vwlkApprView.getAllDocumentsByKey(sessionScope.EmployeeID);
if(collDocAppr.getCount() != 0){
return collDocAppr;
}
return null;}]]></xp:this.value>
<xp:panel id="pnlFG">
<xp:this.data>
<xp:dominoDocument formName="frmAppraisal" var="appraisalDoc"
action="editDocument" documentId="#{javascript:apprDoc.getUniversalID();}">
<xp:this.querySaveDocument><![CDATA[#{javascript:var apprDoc:NotesDocument = appraisalDoc.getDocument();
if(requestScope.SubmitFG == true){
apprDoc.replaceItemValue("CurrFGRRStatus","1");
apprDoc.save();
}}]]></xp:this.querySaveDocument>
</xp:dominoDocument>
</xp:this.data>
<xp:tr>
<xp:td styleClass="tdCls" style="width:2%">
<xp:label id="SrNo">
<xp:this.value><![CDATA[#{javascript:var index = parseInt(docIndex)
index = index + 1;
index.toString();}]]></xp:this.value>
</xp:label>
</xp:td>
<xp:td styleClass="tdCls" style="width:20.0%">
<xp:label id="ApeName">
<xp:this.value><![CDATA[#{javascript:return apprDoc.getItemValueString("AppraiseeName");}]]></xp:this.value>
</xp:label>
</xp:td>
<xp:td styleClass="tdCls" style="width:15.0%">
<xp:label id="ApeGrade">
<xp:this.value><![CDATA[#{javascript:return apprDoc.getItemValueString("Appraisee_Grade");}]]></xp:this.value>
</xp:label>
</xp:td>
<xp:td styleClass="tdCls" style="width:15.0%">
<xp:div style="text-align:center">
<xp:label id="appeTotImpRate"
style="font-size:10pt;color:rgb(255,0,0);font-weight:bold">
<xp:this.value><![CDATA[#{javascript:return apprDoc.getItemValueDouble("AppeTotImpRate").toFixed(2);}]]></xp:this.value>
</xp:label>
</xp:div>
</xp:td>
<xp:td styleClass="tdCls" style="width:15.0%">
<xp:div style="text-align:center">
<xp:label id="apprTotImpRate"
style="color:rgb(255,0,0);font-size:10pt;font-weight:bold">
<xp:this.value><![CDATA[#{javascript:return apprDoc.getItemValueDouble("ApprTotImpRate").toFixed(2);}]]></xp:this.value>
</xp:label>
</xp:div>
</xp:td>
<xp:td styleClass="tdCls" style="width:15.0%">
<xp:div style="text-align:center">
<xp:label id="revTotImpRate"
style="font-size:10pt;color:rgb(255,0,0);font-weight:bold">
<xp:this.value><![CDATA[#{javascript:return apprDoc.getItemValueDouble("RevTotImpRate").toFixed(2);}]]></xp:this.value>
</xp:label>
</xp:div>
</xp:td>
<xp:td styleClass="tdCls" style="width:10.0%">
<xp:div style="text-align:center">
<xp:comboBox id="appeGrades"
value="#{appraisalDoc.ApperFinalGrade}" style="width:50.0px"
disableClientSideValidation="true">
<xp:this.validators>
<xp:validateRequired>
<xp:this.message><![CDATA[#{javascript:var index = parseInt(docIndex)
index = index + 1;
"Please select a final grade in row number " + index.toString();}]]></xp:this.message>
</xp:validateRequired>
</xp:this.validators>
<xp:selectItem itemLabel="-"
itemValue="">
</xp:selectItem>
<xp:selectItem itemLabel="1"
itemValue="1">
</xp:selectItem>
<xp:selectItem itemLabel="2"
itemValue="2">
</xp:selectItem>
<xp:selectItem itemLabel="3"
itemValue="3">
</xp:selectItem>
<xp:selectItem itemLabel="4"
itemValue="4">
</xp:selectItem>
<xp:selectItem itemLabel="5"
itemValue="5">
</xp:selectItem>
</xp:comboBox>
</xp:div>
</xp:td>
</xp:tr>
</xp:panel>
</xp:repeat>
what about a button with the simple action "save data sources"? That should save all data sources available on the XPage.
The computation of the repeat elements isn't very efficient - the JSF lifecycle will make you lookup the values twice. You could try this instead:
// If we looked them up before we don't need to do anything
if (viewScope.approveIDs) {
return viewScope.approveIDs;
}
// Look up the employee details view to get the employee appraisal details from the current database
var curDB:NotesDatabase = session.getCurrentDatabase();
var vwlkApprView:NotesView = curDB.getView("vwlkAllApprApper");
var collDocAppr:NotesViewEntryCollection = vwlkApprView.getAllEntriesByKey(sessionScope.EmployeeID);
// Don't do a count, slow!
var result = new java.util.Vector();
// Add all unids
var ve:NotesViewEntry = collDocAppr.getFirstEntry();
while (ve != null) {
var nextVe = ve.getNextEntry(ve);
result.add(ve.getUniversalId()); // eventually check to avoid categories?
ve.recyle();
ve = nextVe;
}
viewScope.approveIDs = result.isEmpty() ? null : result;
collDocAppr.recyle();
vwlkApprView.recycle();
return viewScope.approveIDs;
This code (off my memory, so check syntax) has a few notable properties:
Error handling is missing, so please add try { } catch(e ) { } generously
.recyle() is used to release memory
ViewEntryCollection instead of DocumentCollection -> better performance
UNIDs are cached in a Vector, so this needs to run only once
the variable apprDoc now directly contains the unid, saving a document call in the panel
the variable docIndex can be used with viewScope.approveIds.get() to get access to the ID too
you could easily extend the example instead of Stings in the vector use a custom object (bean) and get rid of the data sources (might eventually help performance) if you get all fields into the view, so you can continue to use the viewNavigator

Resources