Xpages radio button validation by groupName? - validation

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.....

Related

Xpages Repeat control inside repeat control

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>

xpages deleted selected documents: other actions

a xpages contain view, and a button with simple action: deleted selected documents
the question: how to insert another action before deleting process, because I need to delete documents on other database.
The docs will be deleted on other database have the same subject the documents will be deleted in view
How to insert another action for it?
Thank you
You need to define the desired number of actionGroups. Something like this:
<xp:button value=" My Button" id="button1">
<xp:eventHandler event="onclick" submit="true" refreshMode="complete">
<xp:this.action>
<xp:actionGroup>
<xp:executeScript>
<xp:this.script><![CDATA[#{javascript://your code in javascript - before the delete method]]>
</xp:this.script>
</xp:executeScript>
</xp:actionGroup>
<xp:actionGroup>
<xp:actionGroup>
<xp:deleteSelectedDocuments view="viewPanel1"
message="Confirm?">
</xp:deleteSelectedDocuments>
</xp:actionGroup>
</xp:this.action>
</xp:button>
You can use the the following code to get a handle to the selected documents in view. No you can delete documents in an other database and after that you can delete the document.
var docIds = getComponent("view1").getSelectedIds()
for(var i=0; i< docIds.length; i++){
var doc:NotesDocument = database.getDocumentByUNID(docIds[i]);
//Manipulating other documents
doc.removePermanently(true)
}

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"

Xpages conditional validation: make a field required only if report is being submitted as final

Doing server-side Xpages conditional validation....
I want the follow validation to kick in only if the Report.Status field = 'Final'. (The users are allowed to submit the report as draft and come back and finish it later, when they submit as draft we don't want to make the fields required.)
How would I go about this?
<xp:inputTextarea style="width:75%" value="#{Report.Agenda}" id="Agenda">
<xp:this.validators>
<xp:validateRequired
message="Question 1 can't be blank">
</xp:validateRequired><!-- (1) -->
</xp:this.validators>
</xp:inputTextarea>
Tried this, didn't work, was still required even if Status field not set to final :{
<xp:inputTextarea style="width:75%" value="#{Report.Agenda}" id="Agenda" defaultValue="5 year agenda">
<xp:this.validators>
<xp:validateRequired message="Question 1 can't be blank"></xp:validateRequired><!-- (1) -->
<xp:validateExpression message="Question 1 can't be blank">
<xp:this.expression><![CDATA[#{javascript:
if (Report.getItemValueString('Status')!='Final') {
return true;
}
else {
return false;
}
}]]></xp:this.expression>
</xp:validateExpression>
</xp:this.validators>
</xp:inputTextarea>
Disable validation for whole XPage in submit button with property disableValidators if field "Status" is not "Final":
var status = getComponent('comboBoxStatus').getSubmittedValue();
if (!status || status !== 'Final') {return true;} return false;
The first code line determines the current value of Status control (e.g. combo box) at validation phase (otherwise it is null). The second line returns a false (= don't disable validators) if Status control is "Final" and otherwise true (= ignore all validators).
This way all validators in XPage get executed only if Status is "Final".
This is a working example:
<xp:comboBox id="comboBoxStatus" value="#{Report.Status}">
<xp:selectItem itemLabel="Start"></xp:selectItem>
<xp:selectItem itemLabel="Final"></xp:selectItem>
</xp:comboBox>
<xp:br />
<xp:inputTextarea
id="inputTextarea1"
value="#{Report.Agenda}"
disableClientSideValidation="true">
<xp:this.validators>
<xp:validateRequired message="Question 1 can't be blank" />
</xp:this.validators>
</xp:inputTextarea>
<xp:br />
<xp:messages
id="messages1"></xp:messages>
<xp:br />
<xp:button
value="Save"
id="button1">
<xp:eventHandler
event="onclick"
submit="true"
refreshMode="complete"
immediate="false"
save="true"
disableValidators="#{javascript:
var status = getComponent('comboBoxStatus').getSubmittedValue();
if (!status || status !== 'Final') {return true;} return false;}">
</xp:eventHandler>
</xp:button>
Please notice that client side validation is disabled with disableClientSideValidation="true"
In case you want to disable validation only for certain elements in XPage then set property "disableValidators" only at those elements.

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