In a selection widget there are two ways to provide the available options, dynamic or static. In the following lines we will discuss how to use them and when.
Static options
They are used when the the options are always the same. Making them static will result in a faster response and better performance of our dialog, but once written, we will not be able to change them. Here is how to do it.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
fieldLabel="Selection example" fieldDescription="Please select" name="./selection" type="select" xtype="selection"> jcr:primaryType="nt:unstructured" text="Value1" value="value1"/> jcr:primaryType="nt:unstructured" text="Value2" value="value2"/> jcr:primaryType="nt:unstructured" text="Value3" value="value3"/> |
In the selection widget example above, we create directly an array in the dialog’s XML code, providing the text to display and the value to save in JCR. But what happens if the options are not always the same?
Dynamic options
If for some reason we have to calculate our options based on some parameters, or this options depend on the content, it would be interesting to have a mechanism to generate them. This mechanism is known as dynamic options.
To generate the options we will use a Java Servlet. This Servlet can be also developed in JavaScript or we can even develop a JavaScript function, but I prefer to left JavaScript for client side validation. Lets see how the code would look like.
1 2 3 4 5 6 7 |
fieldLabel="Selection example" fieldDescription="Please select" name="./selection" type="select" xtype="selection" options="/bin/dynamicdialog/options.json" /> |
First of all in the dialog’s XML instead of having a static options array we have a Servlet path, in which we could also pass parameters in a RESTful way to process them latter in our Servlet.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
package com.example.cq.components.dynamicdialog; import java.io.IOException; import javax.servlet.ServletException; import org.apache.felix.scr.annotations.Component; import org.apache.felix.scr.annotations.Property; import org.apache.felix.scr.annotations.Service; import org.apache.sling.api.SlingHttpServletRequest; import org.apache.sling.api.SlingHttpServletResponse; import org.apache.sling.api.servlets.SlingSafeMethodsServlet; import org.apache.sling.commons.json.JSONException; import org.apache.sling.commons.json.io.JSONWriter; @Service @Component @Property(name = "sling.servlet.paths", value = "/bin/dynamicdialog/options") public class OptionsServlet extends SlingSafeMethodsServlet { @Override protected void doGet(final SlingHttpServletRequest request, final SlingHttpServletResponse response) throws ServletException, IOException { response.setContentType("application/json"); JSONWriter writer = new JSONWriter(response.getWriter()); try { /** * [ { "text":"Test1" }, { "text":"Test2" } ] */ writer.array(); writer.object(); writer.key("text").value("Value1"); writer.key("value").value("value1"); writer.endObject(); writer.object(); writer.key("text").value("Value2"); writer.key("value").value("value2"); writer.endObject(); writer.object(); writer.key("text").value("Value3");</pre> writer.key("value").value("value3");</pre> writer.endObject(); writer.endArray(); } catch (JSONException e) { e.printStackTrace(); } } } |
For the Servlet we extend the SlingSafeMethodsServlet class. We provide the path with the annotation “property” giving as name “sling.servlet.paths” and as value the same path provided in the dialog XML file. The communication will be done, as we ask in the dialog’s path, in JSON format, so it is necessary to set the content type of the Servlet’s response and write the response in a JSON format. In this example, for simplicity, we create a JSON object with the class JSONWriter, with fixed options only to show how it is done, but in a real environment we would take advantage of Java’s possibilities to generate the options dynamically based on our needs. To finish this post, clarify that what you put under “text” is what will be displayed on your dialog and what you put under “value” is what will be saved in CRX.
I hope this post was useful to you, if you have questions or suggestions just let me know. Thanks!
great job!!
sas.
Thank you sas!
Very nice feature!
For similar result, it is possible to use optionProvider under xtype=selection , in this case
optionProvider=function(path, record){var st='/bin/dynamicdialog/options.json'+(new Date().getTime()); return CQ.Util.formatData(CQ.HTTP.eval(CQ.HTTP.noCaching(st))) }
Hi Anonymous,
thanks! I appreciate your feedback, I have to try that.
Hi,
Is there any way to create a tab dynamically in a dialog in cq5.please let me know it that's possible or not .
Thanks in advance .
Hi Sabarno, yes you can, try to execute a JavaScript function in a widget event and within this function execute the .enable() or disable() function of your tab.
Regards,
Alberto
Hi,
Can u please tell me how to access value of selectionchanged event in select xtype. in dialog listener like beforeSubmit
Hi AJAY,
when you invoke a listener some objects are always passed to it, take a look at http://dev.day.com/docs/en/cq/current/widgets-api/ , search for the selectionChanged listener of your component and see which objects are passed to it. Then you will be able to navigate and find what you want. Regards.
hi Alberto,
Thanks for your great examples. I'm very new to CQ5 and have made some basic components so far. I have not as yet created any with actual Java packages and classes. Generally they've just been using JSP's.
With this example, where do you actually put the Servlet? Could you give a contextual diagram of the folder structure for this to work please?
Thanks in advance.
Hi Alisneaky!
as you can see in the code, I placed it at the same package as the sample component "com.example.cq.components.dynamicdialog". With that you have to figure out that it would be a package for all the components "com.example.cq.components" and inside of it you would find the component, in this case I named it "dynamicdialog".
For the Server registration I registered it via path at "/bin/dynamicdialog/options but you could register it in any other path based maybe on your architectural design
To register it as path you would need:
@Property(name = "sling.servlet.paths", value = "/bin/dynamicdialog/options")
There are other ways to register a servlet in Adobe AEM depending on your needs. But in this case I would do it definitely by path. Here you can find more information about this topic: https://sling.apache.org/old-stuff/servlet-resolution.html
Hi I got the dropdown , but after selecting dropdown value, its not geting stored in crxde
Thanks for the replay in advance
Hi,
I got exactly the same bug.
Nothing is stored.
Did you fing a issue ?
Hi,
I found the solution :
writer.object();
writer.key("text").value( value );
writer.key("value").value( key ); // value escaped
writer.endObject();
Set only "text" does not fix the value.
Thank you Julien for your correction and for reading my blog, I'm going to change it now!
Hi Mamsha, yep, there is a bug in the code I posted, instead of name = .selection I should have written name = ./selection. I will correct it now. Thanks!!!
Hi Alberto, Thanks for the reply, but its still not getting stored
Hi,
it is working for me, if you want I can export it as a component and send it to you, so you can compare and see what's wrong.
very Nicely explained….
Thanks a lot……
Finaly works perfectly, Thanks a lot Alberto for this article !
Hi Alberto,
Nice Explanation. Is there a way by which we can the default value of the selection from the dynamically generated list. For eg I would to set value1 as default for the example given above, but don't want to hard code it using defaultValue as it dynamically generated list.
Thanks
Nitin
Hi Alberto,
Can we pass the author entered value for another field(in the same dialog where the dropdown exists) as a parameter to the servlet invoked to fetch JSON response?
Something similar to this
options="/bin/dynamicdialog/options.json?q="${param}