One reason to develop a custom xtype control and use it within an Adobe Experience Manager (AEM) component is because you can dynamically set fields. For example, you can retrieve values from a database and set them in xtype fields. An AEM author can then select the values during design time when they are authoring the AEM web page.

To demonstrate how to dynamically update xtype fields, the selected value in a drop-down control is used to set another field. That is, when an AEM author selects a value from the drop-down control, the selected value is set in a text field, as shown in the following illustration.

DropdownSet

To dynamically set controls within a custom xtype, you use JavaScript. This development discusses how to dynamically set a text field in a custom xtype that is created by following another article.

Note:

This article builds off of the AEM article that creates an AEM component that uses a custom xtype. Before following along with this article, it is strongly recommended that you complete this article: Creating AEM multifield components that support drag and drop and uses custom xtypes.   

To dynamically set fields (or perform other operations with custom xtype fields) that are displayed within a component's dialog, you use the Ext JS, 2.x JavaScript library. For information about this JavaScript library, see http://www.sencha.com/learn/overview-of-extjs-2.

The use case in this development article is to demonstrate how to set a text field with the selection of a drop-down control. In the previous illustration, notice that the value Link is selected from the drop-down control. The selected value is then set in the text field.

The JavaScript application logic to modify xtype fields is defined in the CustomWidget.js file. To define a drop-down control in the CustomWidget.js file, you declare a variable in the CQ.form.CompositeField control, as shown by the following code. Notice the variable named linkType.
 

Ejst.CustomWidget = CQ.Ext.extend(CQ.form.CompositeField, {

    /**
     * @private
     * @type CQ.Ext.form.TextField
     */
    hiddenField: null,

   /**
    * @private
    * @type CQ.Ext.form.TextField
    */
    linkText: null,

    /**
    * @private
    * @type CQ.Ext.form.TextField
    */
    linkHref: null,


    /**
     * @private
     * @type CQ.Ext.form.ComboBox
     */
    linkType: null, 

Next, allocate memory to the linkType variable by using a new operator and specifying CQ.form.Selection, as shown in this code example. 

//DROP DOWN
this.linkType = new CQ.form.Selection({
            type:"select",
            cls:"customwidget-1",
            listeners: {
                selectionchanged: {
                    scope:this,
                    fn: this.updateHidden
                }
            },
            optionsProvider: this.optionsProvider
        });

This code demonstrates how to declare a drop-down control for use in the custom xtype

The type property lets you specify the type of the selection control. This property can be one of the following values:

  • checkbox
  • radio 
  • select
  • combobox

The cls property lets you specify a CSS class that is added to this control. The article on which this one is based shows you how to include CSS files with an AEM component.

The optionsProvider property lets you specify the JavaScript method that is used to populate the drop-down control with data. Notice that this.optionsProvider is assigned to this property. In this example, this.optionsProvider is a configuration of the custom xtype. It is set with the Ejst.x3.provideOptions method, which returns two values that are displayed in the drop-down control.
 

Ejst.x3 = {};

Ejst.x3.provideOptions = function(path, record) {
    // use the return value of this method to populate the dropdown
    return [{
        text:"Button22",
        value:"button"
    },{
        text:"Link",
        value:"link"
    }];
};

Note:

The optionsProvider property that is specified on the /apps/hook/components/content/hero/dialog/items/items/links/items/links/fieldConfig is set to Ejst.x3.provideOptions. This is how this.optionsProvider is linked to Ejst.x3.provideOptions, which is used to populate the drop-down control with data. 

The listeners property lets you specify an event handler for this control.  

listeners: {
                selectionchanged: {
                    scope:this,
                    fn: this.updateHidden
                }
            },

The only event handler that is defined is selectionchanged that is fired when a selection in the drop-down control is changed. In this situation, a method named updateHidden is invoked. The following code example shows the updateHidden method.  

// called when a selection in the drop-down is made
updateHidden: function() {
    var val1 = this.linkType.getValue();
    this.linkText.setValue(val1);
}

In this example, notice that the value that is selected in the drop-down control is retrieved by invoking its getValue method. It is assigned to a variable named val1. Then the value is assigned to the textbox field named linkText by calling its setValue method. This is how you can dynamically read values of a control located in a custom xtype and modify other values. It a matter of setting up the correct event handlers, reading the value from control A and setting control B.

The following code shows the updated CustomWidget.js file.
 

Ejst.CustomWidget = CQ.Ext.extend(CQ.form.CompositeField, {

    /**
     * @private
     * @type CQ.Ext.form.TextField
     */
    hiddenField: null,

   /**
    * @private
    * @type CQ.Ext.form.TextField
    */
    linkText: null,

    /**
    * @private
    * @type CQ.Ext.form.TextField
    */
    linkHref: null,


    /**
     * @private
     * @type CQ.Ext.form.ComboBox
     */
    linkType: null,

    /**
     * @private
     * @type CQ.Ext.form.TextField
     */

    formPanel: null,
    
    constructor: function(config) {
        config = config || { };
        var defaults = {
            "border": true,
            "layout": "table",
            "columns":4
        };
        config = CQ.Util.applyDefaults(config, defaults);
        Ejst.CustomWidget.superclass.constructor.call(this, config);
    },

    // overriding CQ.Ext.Component#initComponent
    initComponent: function() {
        Ejst.CustomWidget.superclass.initComponent.call(this);
        //Hidden Field
        this.hiddenField = new CQ.Ext.form.Hidden({
            name: this.name
        });

        this.add(this.hiddenField);

		//DROP DOWN

       this.linkType = new CQ.form.Selection({
            type:"select",
            cls:"customwidget-1",
            listeners: {
                selectionchanged: {
                    scope:this,
                    fn: this.updateHidden
                }
            },
            optionsProvider: this.optionsProvider
        });
        this.add(new CQ.Ext.form.Label({
            cls:"customwidget-label",
            text: "Type"}));
        this.add(this.linkType);

        //Link Text

        this.linkText = new CQ.Ext.form.TextField({
            cls:"customwidget-2",
            id:"valueTxt",
            listeners: {
                change: {
                    scope:this,
                    fn:this.updateHidden
                }
            }
        });
        this.add(new CQ.Ext.form.Label({
            cls:"customwidget-label",
            text: "Text"}));
        this.add(this.linkText);

        //Link HREF Starts

        this.linkHref = new CQ.Ext.form.TextField({
            cls:"customwidget-3",
            listeners: {
                change: {
                    scope:this,
                    fn:this.updateHidden
                }
            }
        });
        this.add(new CQ.Ext.form.Label({
            cls:"customwidget-label",
            text: "URL"}));
        this.add(this.linkHref);

        //Link HREF ends

    },

    // overriding CQ.form.CompositeField#processPath
    processPath: function(path) {
        console.log("CustomWidget#processPath", path);
		this.linkType.processPath(path);
        this.linkType.processPath(path);
    },

    // overriding CQ.form.CompositeField#processRecord
    processRecord: function(record, path) {
        console.log("CustomWidget#processRecord", path, record);
        this.linkType.processRecord(record, path);
        this.linkType.processRecord(record, path);
    },

    // overriding CQ.form.CompositeField#setValue
    setValue: function(value) {
        var parts = value.split("\\");
        //this.linkType.setValue(parts[0]);
        this.linkType.setValue(parts[0]);
        this.linkText.setValue(parts[1]);
        this.linkHref.setValue(parts[2]);
        this.hiddenField.setValue(value);

    },

    // overriding CQ.form.CompositeField#getValue
    getValue: function() {
        this.getRawValue();
        return this.getRawValue();
    },

    // overriding CQ.form.CompositeField#getRawValue
    getRawValue: function() {
	   return this.linkType.getValue() + "\\" +
               this.linkText.getValue() + "\\" +
               this.linkHref.getValue();
    },

    // private
    updateHidden: function() {
        //alert('customwidget updatehidden');

	var val1 = this.linkType.getValue(); 
        this.linkText.setValue(val1);

        
    }



});

// register xtype
CQ.Ext.reg("ejstdate", Ejst.CustomWidget);

//------------------------------------------------------------------------------

Ejst.x3 = {};

Ejst.x3.provideOptions = function(path, record) {
    // do something with the path or record
    return [{
        text:"Button22",
        value:"button"
    },{
        text:"Link",
        value:"link"
    }];
};

Simply replace the CustomWidget.js code in that article with the changes made in the CustomWidget.js from this article. When you select a value from the drop-down value, it is set in the text field.  

Note:

If you get an error saying the custom xtype cannot be located, ensure that you place this line of code in the hero.jsp: <cq:includeClientLib categories="cq.nookhero" />. This clientlib defines the custom xtype. 

See also

Congratulations, you have just created an AEM xtype component that dynamically updates other fields. Please refer to the AEM community page for other articles that discuss how to build AEM services/applications.

This work is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License  Twitter™ and Facebook posts are not covered under the terms of Creative Commons.

Legal Notices   |   Online Privacy Policy