XPages. Hide column in DataTable - 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.

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

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

XPage datatable and pager issue

On my XPage, I have a series of search filters (State, First Name and Last Name). The search button triggers the population of the datatable which is bound to a Managed Bean.
The datatable initially gets populated with rows of data. However when I click on Next (in the pager), instead of loading the next 5 rows, it returns no more data. I KNOW the datatable is getting the right number of rows because if I change the Repeat limit in the datatable to 10, they all display. Also, the number of pages in the pager is 2 (which is the correct number).
Any ideas what could be causing this?
Thanks,
Dan
Code for the datatable:
<xp:dataTable rows="5" id="studentTable" var="currentStudent"
style="width:400.0px" value="#{studentlist.students}">
<xp:column id="firstnameColumn" style="font-weight:bold">
<xp:this.facets>
<xp:span xp:key="header">
<xp:span style="font-weight:bold">
First Name
</xp:span>
</xp:span>
</xp:this.facets>
<xp:text escape="true" id="firstnameField"
value="#{currentStudent.firstname}">
</xp:text>
</xp:column>
<xp:column id="column1">
<xp:text escape="true" id="middleinitialField"
value="#{currentStudent.middleName}">
</xp:text>
<xp:this.facets>
<xp:span xp:key="header">
<xp:span style="font-weight:bold">
Middle Name
</xp:span>
</xp:span>
</xp:this.facets>
</xp:column>
<xp:column id="lastnameColumn" style="font-weight:bold">
<xp:this.facets>
<xp:span xp:key="header">
<xp:span style="font-weight:bold">
Last Name
</xp:span>
</xp:span>
</xp:this.facets>
<xp:text escape="true" id="lastnameField"
value="#{currentStudent.lastname}">
</xp:text>
</xp:column>
<xp:column id="idColumn">
<xp:this.facets>
<xp:span xp:key="header">
<xp:span style="font-weight:bold">ID</xp:span>
</xp:span>
</xp:this.facets>
<xp:text escape="true" id="computedField1"
value="#{currentStudent.id}">
</xp:text>
</xp:column>
<xp:this.facets>
<xp:pager layout="Previous Group Next" xp:key="header"
id="pager1" for="studentTable" partialRefresh="true">
</xp:pager>
</xp:this.facets></xp:dataTable>
Code behind the button:
var state=getComponentValue('state');
var firstName=document1.getItemValueString("firstName");
var lastName=document1.getItemValueString("lastName");
if(state == "--" || firstName == "" || lastName == "")
{
//do nothing
}
else{
studentlist.setConnDB("jdbc:sqlserver://XX.XX.X.XX:1433;DatabaseName=dan_test");
studentlist.setConnUserName("test");
studentlist.setConnPassword("Password1");
studentlist.setSQLQuery("SELECT FirstName,MiddleName,LastName,ID FROM TestStudents WHERE FirstName Like '"+firstName+"%' AND LastName Like '"+lastName+"%' AND State = '"+state+"' ORDER BY LastName ASC");
I'm making some assumptions here without seeing your MBean code, but hope to point you in the right direction nonetheless...
Ensure you are restoring the datamodel within the studenLists bean during invocations of the getStudents() call. I see you have value="#{studentlist.students}" in the XSP fragment above... that should map to a getStudents() method on the bean returning a DataModel of Student objects or the like... presumably yes? So, a couple of things to bear in mind here... ensure the bean is in at least viewScope (preferably) and that you "restore the wrapped data" in the getStudents() method based on a non-transient buffer (eg: ArrayList that is holding the current set of filtered "student" objects - and make sure that the buffer of Student objects is serializable - critical for "Disk Persistence"!
If you use this approach, the Pager will always be "paging" against an up-to-date restored datamodel for each subsequent paging request posted against the current view - the page index etc being internally managed by the DataModel object.
eg:
1. No restoration:
...
private transient DataModel studentSearchResults;
private transient List searchResults;
...
public DataModel getStudents() {
if (null == studentSearchResults) {
studentSearchResults = new ListDataModel();
}
return studentSearchResults;
}
versus:
2. With restoration:
...
private transient DataModel studentSearchResults;
private List searchResults;
...
public DataModel getStudents() {
if (null == studentSearchResults) {
studentSearchResults= new ListDataModel();
if(null != searchResults){
studentSearchResults.setWrappedData(searchResults);
}
}
return studentSearchResults;
}
Do you also lose the data if you add another button that just partially refreshes the dataTable? That should identify if it's a problem with managed bean properties being reset (in which case the contents of the dataTable would disappear) or a problem with paging (in which case they wouldn't).

Resources