I'm running around in circles...
I'll try to explain what I'm trying to do: we have an XPage in a Notes database for a specific document (all web). We also have defined our own forms inside the database. When the document is opened in XPages, the form is retrieved and the fields are populated. That works, I'm glad to say.
Then, we defined some kind of subform. The idea is that the subform displays specific fields in a different way. There can be multiple subforms attached to a form. All these elements are stored in custom controls, say ccForm, ccSubform and ccField.
Upon opening the document, I get the NotesXspDocument object which I can pass to ccForm. The custom control fetches the form definition, and uses a repeat control to generate ccField and a few ccSubform controls. These get passed a lot of parameters, e.g. the current document as a dataSource parameter. When there's a subform, data is copied from the main document and stored (differently) in a temporary document, declared inside ccSubform. The subform opens and reads a different form definition and generates its own ccField controls, using yet another repeat control.
So the NotesXspDocument is created at the top and passed to all controls using a DataSource parameter. The data related to the subform however is stored in a temporary NotesDocument.
My problems:
Awaiting your replies...
Thanks!
update
Current ccSubform, with some debugging:
<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core" xmlns:xc="http://www.ibm.com/xsp/custom"
xmlns:xe="http://www.ibm.com/xsp/coreex" enableModifiedFlag="true" id="ccSubForm">
<xp:this.data>
<xp:dominoDocument var="docTemp" ignoreRequestParams="true">
<xp:this.querySaveDocument><![CDATA[#{javascript:dprint("subform qSD")}]]></xp:this.querySaveDocument>
<xp:this.postNewDocument><![CDATA[#{javascript:var sf= new ccAnyForm(docTemp,compositeData.formName);
viewScope.put(compositeData.formName, sf);}]]></xp:this.postNewDocument>
</xp:dominoDocument>
</xp:this.data>
<xp:this.afterRestoreView><![CDATA[#{javascript:try {
dprint("aRV: " + getClientId("ccSubForm"))
var sf= viewScope.get(compositeData.formName);
dprint("sf= " + sf);
if(!sf)
return;
var mdoc:NotesXspDocument= compositeData.dataSource;
var fields= sf.getFields();
for(var fi in fields) {
var fieldName= fields[fi].name;
var values= [];
for(var i= 0; i<rows.size(); i++) {
var tmp= docTemp.getItemValue(fieldName+"$"+i);
values.push(tmp);
dprint(fieldName + "[" + i + "]= " + tmp);
}
mdoc.replaceItemValue(fieldName, values)
}
}catch(e) {
dprint(e);
}}]]></xp:this.afterRestoreView>
<xp:this.beforePageLoad><![CDATA[#{javascript:dprint("bPL: " + getClientId("ccSubForm"))
}]]></xp:this.beforePageLoad>
<xp:tr>
<xp:td styleClass="label">
<xp:text escape="true" value="#{javascript:compositeData.label}"></xp:text>
</xp:td>
<xp:td>
<xp:panel styleClass="subform">
<xp:table style="width:100%" cellspacing="1" cellpadding="0">
<xp:tr>
<xp:repeat var="thisfield" indexVar="coli">
<xp:this.value><![CDATA[#{javascript:var sf= viewScope.get(compositeData.formName);
if(!sf)
return;
var mdoc:NotesXspDocument= compositeData.dataSource;
var fields= sf.getFields();
fields}]]></xp:this.value>
<xp:td styleClass="label">
<xp:text escape="true" value="#{javascript:thisfield.label}"></xp:text>
</xp:td>
</xp:repeat>
</xp:tr>
<xp:repeat rows="#{javascript:compositeData.rows}" disableTheme="true" var="row" indexVar="rowi">
<xp:this.value><![CDATA[#{javascript:var sf= viewScope.get(compositeData.formName);
if(!sf)
return;
var rows= [];
var fields= sf.getFields();
for(var fi in fields) {
var fieldName= fields[fi].name
var values:java.util.Vector= mdoc.getItemValue(fieldName);
if(values) {
for(var i= 0; i<values.size(); i++) {
rows[i]= i+1;
docTemp.replaceItemValue(fieldName+"$"+i, values[i])
}
}
}
return rows;}]]></xp:this.value>
<xp:tr>
<xp:repeat var="currfield" indexVar="coli">
<xp:this.value><![CDATA[#{javascript:var sf= viewScope.get(compositeData.formName);
if(!sf)
return;
var rows= [];
var fields= sf.getFields();
return fields}]]></xp:this.value>
<xp:td>
<xp:this.styleClass><![CDATA[#{javascript:compositeData.dataSource && compositeData.dataSource.isEditable && compositeData.dataSource.isEditable() && !compositeData.isEditable? "data readonly": "data"}]]></xp:this.styleClass>
<xc:ccfieldType="#{javascript:currfield.type}"
fieldLabel="#{javascript:currfield.label}" fieldTitle="#{javascript:currfield.title}"
fieldValue="#{javascript:currfield.value}" fieldIcon="#{javascript:currfield.icon}"
dataSource="#{javascript:docTemp}" formSource="#{javascript:compositeData.formSource}"
<xc:this.rendered><![CDATA[#{javascript:try {
return af? true: false;
} catch(e) {
return false;
}}]]></xc:this.rendered>
<xc:this.fieldName><![CDATA[#{javascript:currfield.name + "$" + rowi}]]></xc:this.fieldName>
<xc:this.fieldIdName><![CDATA[#{javascript:'id'+currfield.name+"$"+rowi}]]></xc:this.fieldIdName>
<xc:this.fieldUniqueName><![CDATA[#{javascript:'unique'+currfield.name+"$"+rowi}]]></xc:this.fieldUniqueName>
</xc:ccDynamicField>
</xp:td>
</xp:repeat>
</xp:tr>
</xp:repeat>
</xp:table>
</xp:panel>
</xp:td>
</xp:tr>
</xp:view>
You need to take one step back and revisit the approach. XPages doesn't limit you to Documents as data sources. It allows binding to Java beans .... and that points to the solution.
Step 1: for each 'special handling' custom control make one bean that gives you exactly what you need.
Step 2: Design one bean to be used as object data source in the main form. The object data source can be designed so you load a document. Don't try to store the document, only the field values and the unid so you can later save it back
Step 3: design properties in that object datasource that return the beans from step 1
Step 4: design your custom controls to take the bean a parmeter. Be specific with the datatype. You can use #{objDatasource.propname} to provide the parameter. Inside the custom controls use standard EL to bind the beans.
Now when you save the data source you have all data inside your main bean and a very clean layout.
Does that work for you?