Expand my Community achievements bar.

SOLVED

Dynamically generated dialogs

Avatar

Level 4

Is there any way to create a dynamically generated dialog?

For example, in my repo, I have an 'array' in a string property '[true, false, false, true]', which can have any number of values in it. I would be interested in having a dialog that contains x number of checkboxes that could be used to change the values in the array depending on if they are checked or not.

Given that the array size is variable I cannot write an XML file for the dialog as I won't know how many checkboxes to add. Is it therefore possible to create a dialog that can have a variable number of checkboxes depending on how many values there are in the array?

1 Accepted Solution

Avatar

Correct answer by
Level 4

Just a quick follow up on this with my solution in case anybody else comes across this thread:

Background: The data I have is two multidimensional arrays, one holding a series of times and the other boolean values that indicate if an event is sold out at a particular time, e.g.:

times = [[12:00,13:00],[12:00],[17:00,18:00]]

soldOut = [[true,false],[false],[true,false]]

Each set of times is representative of a single day (the arrays above are three day's worth of data).

The user has the ability to add new dates and new times to the repo via another dialog. The problem I had was to create a dynamic dialog that could have x number of checkboxes for the varying number of boolean values in the soldOut array. In the example above, I would need five checkboxes, but if a new time was added then I would need six, etc...

I ended up using a custom xtype to create the varying number of checkboxes:

for(var i=0; i<this.soldOutArray.length; i++) { for(var j=0; j<this.soldOutArray[i].length; j++) { var clsNum = 'customwidget-' + (i+1); var onOff = null; if(this.soldOutArray[i][j] == "true") {     onOff = true; } else {     onOff = false; } window["soldOut" + i] = new CQ.Ext.form.Checkbox({ cls: clsNum, boxLabel: this.timesArray[i][j], checked: onOff, listeners: { change: { scope: this, fn: this.updateHidden }, check: { scope: this, fn: this.updateHidden } } }); this.add(window["soldOut" + i]); } }

This code is from the declaration of the custom xtype and features a pair of nested loops iterating over the values in the sold out array. The default value for the checkboxes is set by the value from the array.

This presents the user with checkboxes for each of the times that have been added and can be toggled on and off to indicate if the time has sold out.

To save the data back to the repo, I have a beforesubmit listener on the dialog:

function saveSoldOutArray(dialog) {     //I want to save the data to a different node in the repo var soldOutField = dialog.getField('../../../../jcr:soldOut'), datesPanel = dialog.getField('./soldOutMultiField'), datesSubpanels = datesPanel.findByType('SoldOutMultiField'), items = datesSubpanels[0].items.items; for(var i=0; i<items.length; i++) { //Repopulate the sold out array with the new values of the checkboxes } soldOutField.setValue(JSON.stringify(soldOutArray)); }

View solution in original post

5 Replies

Avatar

Level 10

A Dialog is only a hierarchy of JCR Nodes with properties. So you can use the JCR API to build this hierarchy via code. So - the answer to your question yes - you can use the JCR API to build a tree of JCR nodes that would represents a dialog.

However - I am not aware of any example of this or article - but we do have an article that shows you how to create nodes with JCR API

https://helpx.adobe.com/experience-manager/using/programmatically-accessing-cq-content-using.html

Most ppl build the dialog manually using CRXDE lite or Eclipse - not through code. 

Avatar

Level 4

Hey, thanks for the response.

I've been having a look at this and have come up with this listener for the dialog:

function(dialog){ var dialogItems = dialog.initialConfig.items.items.items; var newItems = {'jcr:primaryType':'cq:Widget', name:'${path of property to view}', stateful:false, xtype:'textfield', msgTarget:'qtip', anchor:'94%'}; dialog.initialConfig.items.items.items[dialogItems.length] = newItems; return true; }

This inspects the dialog and tries to add a new items (in this case a new textfield) to the initialConfig for the dialog.

I wonder if this is the way to go - I don't know the process for constructing the dialog and if this is even possible. Is there a way to intercept the construction of the dialog and mimic the presence of an extra widget as if it was in the repo?

Do you know what listeners are available to a node with xtype=dialog that I can test with? I have tried loadcontent but that doesn't work.

Avatar

Level 10

If you are using a classic Ui component, there is a rich set of listeners. See this article to see API reference and coding xtypes using listeners to update fields. http://scottsdigitalcommunity.blogspot.ca/2014/01/dynamically-updating-aem-custom-xtype.html?m=0.

Avatar

Correct answer by
Level 4

Just a quick follow up on this with my solution in case anybody else comes across this thread:

Background: The data I have is two multidimensional arrays, one holding a series of times and the other boolean values that indicate if an event is sold out at a particular time, e.g.:

times = [[12:00,13:00],[12:00],[17:00,18:00]]

soldOut = [[true,false],[false],[true,false]]

Each set of times is representative of a single day (the arrays above are three day's worth of data).

The user has the ability to add new dates and new times to the repo via another dialog. The problem I had was to create a dynamic dialog that could have x number of checkboxes for the varying number of boolean values in the soldOut array. In the example above, I would need five checkboxes, but if a new time was added then I would need six, etc...

I ended up using a custom xtype to create the varying number of checkboxes:

for(var i=0; i<this.soldOutArray.length; i++) { for(var j=0; j<this.soldOutArray[i].length; j++) { var clsNum = 'customwidget-' + (i+1); var onOff = null; if(this.soldOutArray[i][j] == "true") {     onOff = true; } else {     onOff = false; } window["soldOut" + i] = new CQ.Ext.form.Checkbox({ cls: clsNum, boxLabel: this.timesArray[i][j], checked: onOff, listeners: { change: { scope: this, fn: this.updateHidden }, check: { scope: this, fn: this.updateHidden } } }); this.add(window["soldOut" + i]); } }

This code is from the declaration of the custom xtype and features a pair of nested loops iterating over the values in the sold out array. The default value for the checkboxes is set by the value from the array.

This presents the user with checkboxes for each of the times that have been added and can be toggled on and off to indicate if the time has sold out.

To save the data back to the repo, I have a beforesubmit listener on the dialog:

function saveSoldOutArray(dialog) {     //I want to save the data to a different node in the repo var soldOutField = dialog.getField('../../../../jcr:soldOut'), datesPanel = dialog.getField('./soldOutMultiField'), datesSubpanels = datesPanel.findByType('SoldOutMultiField'), items = datesSubpanels[0].items.items; for(var i=0; i<items.length; i++) { //Repopulate the sold out array with the new values of the checkboxes } soldOutField.setValue(JSON.stringify(soldOutArray)); }

Avatar

Level 10

A Custom xype is the way to proceed here.

Likewise - if you are ever using Touch UI, then you need to code a custom Sling Resource type - which behaves much like a custom xtype in that you can code your own application logic for a field in a touch ui dialog. 

See this example on how to create a custom sling resource type for use in a Touch UI component. 

Creating a custom Experience Manager sling:resourceType for Touch UI