PermaLink XPages Example part 2: Generating dynamic editable fields for a document collection06/16/2008 03:50 AM
Domino 8.5 - XPages
* please note: This example has been updated to work with 8.5 Gold.

I built on the previous XPage example, the Customer Orders application, to demonstrate how to generate dynamic fields from a document collection.  There is a sample database for you to download as well as a powerpoint presentation that explains the steps involved.

Over the years I have developed different techniques to handle dynamic fields in Domino applications.  I'm sure many of you have also tackled this issue in various ways.  In XPages there are built in controls that you can utilize to address this issue.

In the previous example I demonstrated how XPages allows you to bind your controls on the page to multiple datasources.  In this example I take it up a notch by showing how you can repeat a panel control that is bound to a document multiple times, thereby binding edit controls to a collection of Notes documents.  XPages maintains the binding so that all the documents are updated from a single button with a single simple action "Save Datasources".

Here's the use case: When a Customer Order is created there could be multiple items the customer is ordering.  We should give the user the ability to add new items dynamically by clicking a button.  The button will create a new response document and then reload the page.  The repeat control will generate the following editable fields for all the response documents: Item Number, Price, and Quantity.

Here is a screen shot:
Image:John's Blog - XPages Example part 2: Generating dynamic editable fields for a document collection

Here are the downloads:
- CustomerOrders.nsf
- step-by-step powerpoint

Download the application and try it out.  Contact me if you have any questions via posting or email.  My contact information is in the powerpoint.

John

Technorati:
This page has been accessed 5874 times. .
Comments :v

1. Vidyasagar07/18/2008 01:43:34 AM


Nice one. Its working fine. But is there a way to add an X page in the repeat control and get the same functionality?




2. John Mackey07/18/2008 04:35:50 AM


Vidyasagar, you can add a custom control in a repeat control. A custom control is basically an XPage itself, similar to a subform in Domino.

The multi-file upload sample is an example of this. Take a look at this post: { Link }




3. veena12/15/2008 07:23:28 PM


Thanks for your good example and step by step ppt, I have problem while running the "CustomerOrders.nsf " on my own server, the error message in browser is: "Error 500
HTTP Web Server: Command Not Handled Exception", and the error message on server console is: "HTTP JVM: SEVERE: CLFAD####E: Exception thrown". what's wrong?




4. hector amato02/03/2009 04:19:02 AM


After having a look at the HTNL generated, I see that there is a DIV element the corresponds to the Repeat Control. i would need to use an outer table instead of an inner one, and then repeat only the rows. The problem is that the HTML comes as
<TABLE>
<DIV id="... (repeat)
<TR>...
<TR>...
....
</TABLE.
so it is not well formed.

Is there any way to remove the DIV from the output HTML ?. I have seem that the repeat has a property removerepeat that should do the job, but it dows not work. Any hints ?




5. John Mackey02/03/2009 11:49:18 AM


@Hector, Yes I completely understand your issue with using an inner table. You might want to look at using the "Data Table" control instead of a repeat control. It seems to be in between a view control and a repeat control. Here's a link to the wiki where there is a great demo by Paul Hannan from IBM.

{ Link }

Also, there is an additional entry explaining how to remove the HTML tags completely: { Link }

Regards,
John




6. naresh03/03/2010 02:23:43 AM


:-




7. Raphael Costa07/02/2010 12:52:01 PM


Hello John,
First, I like to congrat you for this nice article.
Now, get to the point:
I'am developing a web XPages application, and I trying to use your techinique of using multiple Datasources.

I gotta a main document that have 0 or more dependent documents. So, I desined a XPage with a repeat control that shows the associated documents:

<xp:repeat id="repeat1" rows="30" var="entryExecutante">

The formula that Im using inside the repeat control is:

<xp:this.value><![CDATA[#{javascript:var arrayExecutante=null;
var index=0;
if(sessionScope.acaoVCP=="novoExecutante"){
arrayExecutante=new Array();
//arrayExecutante[index++]=sessionScope.dadosNovoExecutante;
arrayExecutante[index++]={
action: null,
NoteID: null,
CodigoGerencia: vcp.getValue("ca_vcpCodigoGerencia"),
CodigoVCP: vcp.getValue("ca_Codigo"),
Gerencia: vcp.getValue("ca_vcpGerencia"),
CodigoAN: vcp.getValue("ca_vcpCodigoAN")
}
}

var dc = viDu001.getAllDocumentsByKey("C~"+vcp.getValue("ca_Codigo")+"~fo_ExecutanteVCP~", false);
if(dc.getCount()>0){
if(arrayExecutante==null) arrayExecutante=new Array();
for(var i=1; i<=dc.getCount(); i++)
arrayExecutante[index++]={
NoteID: dc.getNthDocument(i).getNoteID(),
action: vcp.isEditable()?"editDocument":"openDocument",
CodigoGerencia: vcp.getValue("ca_vcpCodigoGerencia"),
CodigoVCP: vcp.getValue("ca_Codigo"),
Gerencia: vcp.getValue("ca_vcpGerencia"),
CodigoAN: vcp.getValue("ca_vcpCodigoAN")
};
}

return arrayExecutante;}]]></xp:this.value>

Basically, this formula creates a array of objects that will initialize the custom control that contains the datasource of the associted doc.
At the beginning, I test if the user is creating a new document (sessionScope.acaoVCP=="novoExecutante", this sessionScope variable is set through a button), if so, it sets the first position on the array with a object with action=null and NoteID=null, signaling that the datasource correspond a new document.

The button that shows that signals the repeat to put the empty custom control at the beggining follows:

<xp:button value="Incluir Executante" id="button5" styleClass="customButton">
<xp:this.rendered><![CDATA[#{javascript:vcp.isEditable() && sessionScope.acaoVCP!="novoExecutante"}]]>
</xp:this.rendered>
<xp:eventHandler event="onclick" submit="true" refreshMode="partial" immediate="true" refreshId="pnExecutantesForm">
<xp:this.action>
<xp:executeScript>
<xp:this.script><![CDATA[#{javascript:sessionScope.acaoVCP="novoExecutante";}]]>
</xp:this.script>
</xp:executeScript>
</xp:this.action>
</xp:eventHandler>
</xp:button>

Note that the event only tells the application to refresh partial, the "pnExecutantesForm" is the <xp:panel> that contains the button and the repeat control.

Inside the repeat, I put a custom control with a datasource to the associated document.

<xc:ccNovoExecutante
action="#{javascript:entryExecutante.action}"
CodigoAN="#{javascript:entryExecutante.CodigoAN}"
CodigoGerencia="#{javascript:entryExecutante.CodigoGerencia}"
CodigoVCP="#{javascript:entryExecutante.CodigoVCP}"
Gerencia="#{javascript:entryExecutante.Gerencia}"
NoteID="#{javascript:entryExecutante.NoteID}">
</xc:ccNovoExecutante>

This custom control provides a few properties to allow me to control its behavior.
The custom control's Datasource is defined by the compositeData.action and the compositeData.NoteID:

<xp:this.data>
<xp:dominoDocument var="docNewExecutante"
formName="fo_ExecutanteVCP" ignoreRequestParams="true"
computeWithForm="onsave"
documentId="#{javascript:return compositeData.NoteID}"
action="#{javascript:compositeData.action}">

<xp:this.postNewDocument>
<xp:executeScript>
<xp:this.script><![CDATA[#{javascript:requestScope.CodigoNovoExecutante=@Unique()
docNewExecutante.replaceItemValue("ca_exvCodigoGerencia", compositeData.CodigoGerencia);
docNewExecutante.replaceItemValue("ca_exvCodigoVCP", compositeData.CodigoVCP);
docNewExecutante.replaceItemValue("ca_Codigo", requestScope.CodigoNovoExecutante)}]]></xp:this.script>
</xp:executeScript>
</xp:this.postNewDocument>
</xp:dominoDocument>
</xp:this.data>

The main objective here is, allow the user to view the associated docs through this custom control in the main page, and, when the user clicks the button to add a new associated doc, the application shows in the first position a empty form to input the information.

THE PROBLEM:

When I click the button, instead of show a empty form, it shows a form whith the values of the last line of the associated docs, and scramble all the associated docs that it had already show in a correct way.
The strange thing is, when I put only the part of the code that put the object that intialize the custom control to show a empty form, it works. But, when I mixed up, it gets scramble.

Do you have any idea why this is happening?
Any help will be welcome.




8. Raphael Costa07/05/2010 09:42:28 AM


Hi John,

I figured out how to solve this "bug".
I put the object, that put the custom control as a "newDocument", in the end of the array.
<xp:repeat id="repeat1" rows="30" var="entryExecutante"
disableTheme="true">
<li>

<xc:ccNovoExecutante action="#{javascript:entryExecutante.action}"
CodigoAN="#{javascript:entryExecutante.CodigoAN}"
CodigoGerencia="#{javascript:entryExecutante.CodigoGerencia}"
CodigoVCP="#{javascript:entryExecutante.CodigoVCP}"
Gerencia="#{javascript:entryExecutante.Gerencia}" NoteID="#{javascript:entryExecutante.NoteID}">
</xc:ccNovoExecutante>
</li>
<xp:this.value><![CDATA[#{javascript:var arrayExecutante=null;
var index=0;

var dc = viDu001.getAllDocumentsByKey("C~"+vcp.getValue("ca_Codigo")+"~fo_ExecutanteVCP~", false);
if(dc.getCount()>0){
if(arrayExecutante==null) arrayExecutante=new Array();
for(var i=1; i<=dc.getCount(); i++)
arrayExecutante.push({
NoteID: dc.getNthDocument(i).getNoteID(),
action: (vcp.isEditable()?"editDocument":"openDocument")
/*CodigoGerencia: dc.getNthDocument(i).getItemValueString("ca_exvCodigoGerencia"),
CodigoVCP: dc.getNthDocument(i).getItemValueString("ca_exvCodigoVCP"),
Gerencia: dc.getNthDocument(i).getItemValueString("ca_exvGerencia"),
CodigoAN: dc.getNthDocument(i).getItemValueString("ca_exvCodigoAN")*/
});
}

if(sessionScope.acaoVCP=="novoExecutante"){
// arrayExecutante=new Array();
arrayExecutante.push({
action: null,
NoteID: null,
CodigoGerencia: vcp.getValue("ca_vcpCodigoGerencia"),
CodigoVCP: vcp.getValue("ca_Codigo"),
Gerencia: vcp.getValue("ca_vcpGerencia"),
CodigoAN: vcp.getValue("ca_vcpCodigoAN")
});
}

return arrayExecutante;}]]></xp:this.value>

</xp:repeat>




Search
Partner with us
Need help on your XPages projects?

Talk to the experts! Read more...
XPage Examples
By Category
About Me
Downloads
My Links
Monthly Archive
Powered by
Blogsphere
Lotus Domino ND7 RSS News Feed RSS Comments Feed Geo URL netcraft RSS Validator Lotus Geek Chris. A. Brandlehner OpenNTF BlogSphere