Dynamically adding the same UserControl multiple times - user-controls

I have a simple UserControl that I've created that simply allows a user to enter the date. For the time being, it has a single Textbox with ID="tbDate". I am trying to dynamically add this control multiple times via (for example) placeholder.Controls.Add(LoadControl()) but am receiving the error "An entry with the same key already exists". I could, perhaps, change the ID of the elements but then it would be difficult to grab the value entered by the user.
Does anyone have an idea on this?
Thanks!

I generate a unique identifier as part of a Component class that I created and then use that value as the Control.ID. You can generate this unique value in any way you'd like but I am storing it as part of a database table. In the end it isn't that important since when the class is instantiated the values are initialized and consistent throughout the run of the application.
The class has a private instance variable:
private Control _control;
When adding the control to the form (and, specifically, the placeholder) I do something similiar to this. Note that c references my created class.
c.Control.ID = c.ComponentName + c.UniqueIdentifier;
phHere.Controls.Add(c.Control);
Then when I need to reference the control at a later point I essentially reverse the steps above:
string component = c.ComponentName + c.UniqueIdentifier;
UserControl uc = (UserControl)ph.FindControl(component);
Hopefully this helps. If you have any questions please feel free to ask. The root of the problem, though, is that the Control.ID must be set in order to avoid the error.
Thanks

Related

Segmented Keys in ACUMATICA

I’ve created new Segmented Keys in ACUMATICA for use in a specific module. I would like to assign the Dimension name dynamically but I noticed it works only with hard code or name like [PXDimension(“VENDOR”)]
Also, I have some limitation to create an IF Conditional inside the customized field… it does not recognize the IF clause (see the image).
I would appreciate any suggestion how to solve this issue.
I haven't seen how your original attempt at PXDimension looked, but I'm going to take a guess and assume you tried to reference a new custom field contained in a setup table, something like:
[PXDimension(typeof(XXMySetup.usrMyCustomField))]
If that's indeed what you tried to do, one very important thing to do is to ensure that you have a view for your table in your graph, otherwise the attribute will not find the table and record in your cache. For instance:
public PXSetup<XXMySetup> XXMySetup;
Without this view declared in the graph, the dimension attribute will not work as expected. It would be nice if a clear exception was thrown in this case - I made the same mistake recently and it would have been helpful.

Dynamic field binding inside a repeat control

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.

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

Why the OnWorkflowItemChanged is different between List and document library?

I am doing a workflow for a document library. I put a OnWorkflowItemChanged, and I want to get the value of the column which is changed. I use the workflowProperties.Item["name"] and use the afterProperties. But when I use the workflowProperties.Item["column name"], I still got the original value. When I use the afterProperties, it's NULL.
Then I make another workflow that is the same as above for a list. I can use the workflowProperties.Item["column name"] to get the new value in OnWorkflowItemChanged.
Has anyone come across this problem before? Can you give me some help?
The question seems to mix up Item with ExtendedProperties. As to why a difference is seen on a List/Document Lib, it might have something to do with versionining or perhaps the internal serialization is different. Anyway, some of my experience is outline below. I hope it may be of use:
Use the GUID (as a Guid object, not a string) to access the Before / After ExtendedProperties field. Using the Display Name in the ExtendedProperties will not work. The documentation on it is wrong. You can use SPList.Fields to go from Display Name to Column ID (Guid).
I bind all "Before" to MyWhatever_PreviousProperties and all "After" to MyWhatever_Properties, only accessing MyWhatever_[Previous]Properties after the appropriate event(s)).

Resources