Dynamic field binding inside a repeat control - xpages

I have a strange thing, I'm using dynamic field binding in a custom control.
The field binding is created like this.
XPage (Datasource "document" is placed here)
Custom Control (String passed in)
(to get errors if there are any)
Repeat (CompositeData is passed to a bean that returns the strings for Rows,columns)
Repeat (repeat 1 variable used for Columns)
Custom Control (fieldname is passed in)
field binding is done like this
#{document[compositeData.fieldName]}
The problem is that when I save the XPage I get an error in the messages control
Document has been saved by another user - Save created a new document as a response to that modified document.
And all fields are cleared.
Any ideas how to debug this or is there something I'm missing?

The "Document has been saved by another user" error is only tip of the iceberg - there are some really strange problems with reapeats that repeats fields that are bound and repeatControls property is set to false. The decoding part of xpages lifecycle cannot handle it properly - the controls will be losing data. You should use repeatControls set to true as Martin suggests.
"Repeat control variable doesn't exists" is probably caused by the property that removes repeats set to true. You can solve this by either changing it to false or by adding additional data context that will keep repeated value.
And finally for this to have add/remove functionality You can use Dynamic Content Control and show(null) hack to rebuild the repeat content.
To manage this complexity better I would advise You to stop using document data source and start creating some managed beans.
If You will follow my suggestions I guarantee that You will get the functionality You are looking for as I have few apps that works great and have this kind of complex data editors in them.

I don't know if it'll help you, but I pass both the document datasource and the field name as parameters to a DynamicField control, and use it like this:
compositeData.dataSource[compositeData.fieldName]
The type of the datasource is com.ibm.xsp.model.DataSource, it's listed as dataInterface under Data Sources.

Do you have repeatControls="true" set for the repeat control?

It sounds like you've got the datasource defined multiple times on the XPage (plus custom controls). Either that or the save button has save="true" but the code saves the document back-end, or code in multiple places saves the same document. I've used the same method of passing the datasource down to the custom control, but that may just be because that was what I saw on a blog.

Related

filtering/searching on a repeat control

In my application, i would like to replace a viewpanel with a repeat control.
However, part of the functionality is there is a UI aspect that allows users to select certain fields (that correspond to the view), and only display the documents that match. The view is doing a filter that allows users to select aspects of the view to create a search (the code is under search of the view) that allows the view panel to be updated with the results of the search.
one of the things that is curious is that the viewpanel has a value of "#{javascript:view2}" vice an actual view name.
The viewpanel defines the search view and the ...
I'd like to be able to apply that same functionality to the repeat control. I don't see those attributes on the repeat control... Any pointers? Its been a while since i've worked with xpages... long enough that I've forgotten a lot already....
TIA !
Read this blog post I did a while back, it should explain what you need.
The view panel doesn't filter anything, it just displays rows from a datasource, same as a repeat control. Indeed you can add components to a ViewPanel's column, pulling from the current row by adding a var property to the dominoView datasource.
The view is bound to #{javascript:view2} (which would be better done by binding to #{view2} - there's no need to call SSJS here). view2 is a dominoView datasource somewhere on your page. The datasource is a wrapper that has properties to capture the settings for filtering and searching that you want to do. At runtime, they are calculated and changes the ViewEntries in the datasource.
Finally there's is the underlying Domino View object available also to LotusScript. This holds and will always hold all entries. The dominoView datasource queries that using the filtering and searching properties and retrieves a ViewEntryCollection or a ViewNavigator.
So whether you use a View Panel, Repeat Control, Data View or whatever else, those are just components to visually represent a collection of ViewEntries or Documents. All can be bound to a dominoView datasource. Where repeat controls and Data Views give you extra power is you can bind them to any kind of collection, not just a dominoView datasource (e.g. DocumentCollection, ViewEntryCollection, multi-value field, Java collection, etc).
I often find that doing the searches in Java and then passing the results to the repeat as a List work better and allow more options. I can get all the information I need in Java and load that into a Map or Tree. This gives me the ability to do custom sorting in the Java class and also to combine data from other views/databases easily. Since the data is now in memory it gets reloaded fast. The only thing you have to watch for is the size of the data. If you have a view with many entries (10K?) you might not want to load everything into memory...
Howard
I'm not sure if you've found a solution yet, but consider using jQuery dataTables. Oliver Busse wrote a very detailed blog post about integrating dataTables into XPages.
To get the specific formatting, I used a repeat control to include the "td", "tr" and "thead" attributes Oliver listed in his blog post.

Retrieving column values in filtered xpages view

I have a view defined on an xpage. I also have several filters (based on the columns) that the user can select and combine to filter the results in the view. I generate a query string based on this that I construct in dominoView.search (doing a complete refresh). What I would like to do is get the results of the search so that I can then update some counts displayed elsewhere on the page. I'm having a hard time figuring out where I can perform this logic, though. I'm trying to use view.getAllEntries() and then iterating over the collection. Sometimes it seems like it works, but other times I seem to be getting the unfiltered view. Someone suggested I explicitly call view.FTSearch inside one of the events (beforePageLoad?) and immediately after do my getAllEntries call, saving the results in viewScope, but I get an "Error while browses Notes view" runtime error when I try to do that. Any pointers? TIA!
EDIT: After studying the xpages lifecycle a bit (which is still a little confusing), I think I can fine-tune my question. This is my first stackoverflow question, so I hope this is okay to do and productive....
As I described, I have a dominoView defined on my xpage. A repeat iterates over the rows of the view, displaying certain fields from the documents. If I define a query in the search property, then the repeat correctly displays the reduced set of documents rather than the complete set. (The query is computed in the search property via SSJS from some variables defined in the viewScope in a combobox's eventHandler.) However, if I try to access the current entries in the view inside of the repeat's rendered section (with SSJS) using myView.getAllEntries (where myView is what's defined as the "value" of the repeat), I am still getting all of the documents, even if a query has been done. It seems like at that point, the view variable has already had its search applied (since the repeat works), so why the differing results? Is there another way to access the view's rows? To complicate this further, this is just a simple experiment that might clarify the problem; as I indicated earlier, I don't actually want to access the view data within the repeat, I want to access it in the rendered or value sections of some comboboxes defined before the repeat in the xpage file.
I hope that makes more sense now....
EDIT #2: I forgot to add that if I manually call FTSearch (or FTSearchSorted) before calling myView.getAllEntries, then I think I can make this work. It just seems unnecessary to have to do that in addition to the view's built-in search.
From what I get you want to iterate over the entries in a view that before has been filtered, i.e. whose resulting entry collection is smaller than the the view itself.
What I don't get (yet) is what you want to do with the result, or what you're axpecting to get from the iteration over your filtered view (you're mentioning some counts to be displayed somewhere else).
Probably a good way is to use the view's .getAllEntriesByKey method which returns a NotesViewEntryCollection object which then can be used for your iteration.
Don't forget to recycle the resulting NotesViewEntry objects; reason for this has been explained several times here at stackoverflow.

How to import two cc both contain compositeData?

I do not know that the question is right? Please do not take it your mind if it is crazy. Actually I am working on xpages application. There I need to do two things, that I want to add the picklist functionality and binding the dynamic data like field_1,field_2,field_3, ... upto n depands on customer choice.I am using the composite data for both custom controls. I can remove the picklist control's composite data and also I can do it by passing the scope variables. But that takes more time than the composite data.
I did not get any error. But the binded documents is not saving.
Is it possible to import the CCs that are having composite Data?
Code for first CC:-
<xc:viewpicklist datasrc="view1" dialogID="dialog1" dialogWidth="700px" dialogTitle="Pick this field value!!!">
<xc:this.viewColumn>
<xp:value>0</xp:value>
<xp:value>1</xp:value>
<xp:value>2</xp:value>
</xc:this.viewColumn>
</xc:viewpicklist>
Code for Second CC:-
<xc:BOM_Partinfo BOM_Partinfo="#{document1}"
TNUM="field#{index+1}" Desc="Desc#{index+1}" quan="Ea#{index+1}"
exp="exp#{index+1}" cap="cap#{index+1}" total="price#{index+1}"
RD="RD#{index+1}" m="manufact#{index+1}"
m_n="manufactnum#{index+1}">
</xc:BOM_Partinfo>
You can read information that is set in the properties of a custom control if it was static in the calling page:
var x = getComponent("yourcomponentid");
x.getPropertyMap().get("parametername");
but you want to propagate a data source from the outer control to the inner control...
You need to plan carefully. If you hand over the data source, then your custom control is dependent on a fixed set of fields in the data source (that would be a parameter of type com.ibm.xsp.model.DocumentDataSource). This would violate the encapsulation principles. So I would recommend you actually hand over data bindings - the advantage: you are very flexible what to bind to (not only data sources, but also beans and scope variables would work then). The trick is you provide the binding name as you would statically type it in (e.g. "document1.subject" or "requestScope.bla" ). In your control you then do
${"#{compositeData.field1}"}
${"#{compositeData.field2}"}
You need one for each field.
You cannot send a document data source to a custom control using composite data parameters.
You can try and use this script instead
http://openntf.org/XSnippets.nsf/snippet.xsp?id=access-datasources-of-custom-controls
Define data source in XP/CC where you want those CCs. Define parameter "dataSourceName" for both CCs. Inside each of them use EL "requestScope[compositeData.dataSourceName].fieldName" everywhere you want to bind to datasource.

Getting a field value from a custom control when there are multiple instances of the custom control

I have an xPage with multiple instances of the same custom control. How do I get to the value of a field on a specific custom control from a button on my xPage.
Normally I would do something like:
ctlName = "radioGroupCMBUAction";
var changeType = getComponent(ctlName).getValue();
If there was only one instance of the control. How would I do this with multiple instances of the control?
Without the code I'm not sure if .getValue() will work as in order for this to happen it will have to pull out a field where as a custom control could have a repeat inside it etc.
Assuming that it will work if each of the customControl instances have an id that is unique from each other it should work fine as each instance should have its own vriables inside it.
Other ideas however could be to pass in a string and use this string as the name of a scoped variable inside the custom control that can be pulled out from anywhere. I've done this before where I created a property on the custom control for a String and inside the custom control use
viewScope[compositeData.customProperty] = value.
then outside the context of the custom control I am aware of the string I passed in so I would be able to pull this value back out. Passing it in means multiple instances won't over write each other.
Or you could write the field in he custom control to a document, either to get it out or as the end solution to your problem of saving it.
Not sure if this can help you..? A while back, I wrote a tip regarding "private" scoped variables:
http://dontpanic82.blogspot.com/2010/03/xpages-tip-regarding-private-scoped.html

Hiding a SharePoint Custom Field Type in Edit and Create mode

I am trying to create a Custom Field Type in SharePoint.
This control has it's value set based on another field in the same list.
Because of this requirement, this field should be displayed only in the Display Mode, and not in the Edit or Create mode.
How do I ensure this?
If I just code the ASCX control to not render a field, the field will show up like this in the Edit and Create mode.
alt text http://www.mannsoftware.com/blog/Lists/Photos/121308_0204_CrossSiteLo6.png
Generally you set the SPField.ReadOnlyField property to True to achieve the desired behaviour for any field. (Don't forget to SPField.Update accordingly!) There is an equivalent CAML attribute for list definitions, I believe.
That said, in your control class deriving from BaseFieldControl, you might just override the RenderFieldForInput() method and not call the base implementation to ensure nothing is rendered during Create or Edit. However, this would still render the field's table row in the form, which is probably not what you want. So to enforce the desired behaviour, use ReadOnlyField and override Update() in your SPField (not field control) class to always have it set to True.
It might be easier to just change this on a list-by-list basis by going to the Advanced section of the List Settings, setting Allow management of content types? to Yes, and then editing your content type to change the value of your field to 'hidden'.
Take a look at this blog post. I think it will give you some ideas. The concept uses different rendering templates based on the mode.
http://sharepoint.nailhead.net/2008/04/creating-rendering-template-that.html
Did you try and set the field as hidden?
http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.spfield.hidden.aspx
Custom FORMS pages for new item and edit item (NewForm.aspx and EditForm.aspx) would be another way to achieve this.
Setting the ShowInEditForm and ShowInNewForm properties solved this for me.

Resources