3

I am trying to create a combobox with a dropdown with a clickable button.

I have overridden the renderTpl and copied the button instantiation code of the datepickers todayBtn. This fiddle shows what I have now, the button is rendered but not yet clickable, the handler is not executed.

What am I missing?

Code:

Ext.define('EnhancedCombo', {
    extend: 'Ext.form.field.ComboBox',
    xtype: 'enhancedcombo',
    footerButtonUI: 'default',
    selAllText: 'Select All',
    initComponent: function() {
        var me = this;
        me.callParent(arguments);
        me.selAllBtn = new Ext.button.Button({
            ui: me.footerButtonUI,
            ownerCt: me,
            ownerLayout: me.getComponentLayout(),
            text: me.selAllText,
            tabIndex: -1,
            ariaRole: 'presentation',
            handler: me.selectAll,
            scope: me
        });
    },
    listConfig: {
        renderTpl: [
            '<div id="{id}-listWrap" data-ref="listWrap"',
                    ' class="{baseCls}-list-ct ', Ext.dom.Element.unselectableCls, '">',
                '<ul id="{id}-listEl" data-ref="listEl" class="', Ext.baseCSSPrefix, 'list-plain"',
                    '<tpl foreach="ariaAttributes"> {$}="{.}"</tpl>',
                '>',
                '</ul>',
            '</div>',
            '<div id="{id}-footerEl" data-ref="footerEl" role="presentation" class="{baseCls}-footer" style="">{%this.renderSelAllBtn(values, out)%}</div>',
            {
                disableFormats: true,
                renderSelAllBtn: function(values, out) {
                    Ext.DomHelper.generateMarkup(values.$comp.ownerCmp.selAllBtn.getRenderTree(), out);
                }
            }
        ],
    },

    selectAll: function() {
        console.log('select all');
        this.getPicker().getSelectionModel().selectAll();
    }
});
Alexander
  • 19,906
  • 19
  • 75
  • 162

2 Answers2

1

As you are using Ext.DomHelper.generateMarkup() so it will return html in form of Array. So you are just appending the html of that button not component.

You could achieve this functionality, you need to use addListener method on picker like this

picker.addListener('afterrender', function(){},scop);

And after that, inside of afterrender event you can add click event by getting dom element by using Ext.dom.Element.down() like this

picker.addListener('afterrender', (comp) => comp.el.down('.selectall').on('click', this.selectAll, comp), me)

FIDDLE

In above fiddle, I have created a demo.

CODE SNIPPET

Ext.application({
    name: 'Fiddle',

    launch: function () {
        var btn = new Ext.button.Button({
            text: 'Working button',
            handler: function () {
                alert('Working button click');
            },
            listeners: {
                afterrender: function () {
                    console.log('afterrender Working button')
                }
            }
        });

        function getBtnHtml() {
            let button = new Ext.button.Button({
                text: 'No wokring button',
                handler: function () {
                    alert('Test 2');
                },
                listeners: {
                    afterrender: function () {
                        console.log('afterrender not Working button')
                    }
                }
            });
            return Ext.DomHelper.generateMarkup(button.getRenderTree(), []).join('')
        }

        Ext.create({
            xtype: 'panel',
            title: 'Demo',
            renderTo: Ext.getBody(),
            layout: 'hbox',
            defaults: {
                flex: 1,
                margin: 10
            },
            items: [btn, {
                xtype: 'panel',
                html: getBtnHtml()
            }]
        })

        Ext.define('EnhancedCombo', {
            extend: 'Ext.form.field.ComboBox',
            xtype: 'enhancedcombo',
            footerButtonUI: 'default',
            selAllText: 'Select All',
            multiSelect: true,
            initComponent: function () {
                this.callParent(arguments);

                var me = this,
                    picker = me.getPicker();

                me.selAllBtn = new Ext.button.Button({
                    ui: me.footerButtonUI,
                    ownerCt: me,
                    ownerLayout: picker.getComponentLayout(),
                    text: me.selAllText,
                    cls: 'selectall',
                    tabIndex: -1,
                    ariaRole: 'presentation',
                    scope: me
                });

                picker.addListener('afterrender', (comp) => comp.el.down('.selectall').on('click', this.selectAll, comp), me);

            },
            listConfig: {
                renderTpl: [
                    '<div id="{id}-listWrap" data-ref="listWrap"',
                    ' class="{baseCls}-list-ct ', Ext.dom.Element.unselectableCls, '">',
                    '<ul id="{id}-listEl" data-ref="listEl" class="', Ext.baseCSSPrefix, 'list-plain"',
                    '<tpl foreach="ariaAttributes"> {$}="{.}"</tpl>',
                    '>',
                    '</ul>',
                    '</div>',
                    '<div id="{id}-footerEl" data-ref="footerEl" role="presentation" class="{baseCls}-footer" style="">{%this.renderSelAllBtn(values, out)%}</div>', {
                        disableFormats: true,
                        renderSelAllBtn: function (values, out) {
                            Ext.DomHelper.generateMarkup(values.$comp.ownerCmp.selAllBtn.getRenderTree(), out);
                        }
                    }
                ],
            },

            selectAll: function () {
                console.log('select all');
                this.getSelectionModel().selectAll();
            }
        });

        Ext.create('EnhancedCombo', {
            renderTo: Ext.getBody(),
            store: ['Test 1', 'Test 2']
        }).expand();

    }
});
halfer
  • 19,824
  • 17
  • 99
  • 186
Narendra Jadhav
  • 10,052
  • 15
  • 33
  • 44
1

Every component has a method finishRender, which is called from the parent component during a render run. As I generate the markup manually through generateMarkup, I also have to call the finishRender method manually after the picker has been rendered before the button can be clicked.

In DatePicker, finishRender of the todayBtn is called from the overridden private finishRenderChildren method. Although I cannot override that private method of my picker, I can call the same finishRender method from an afterrender listener I can add to the picker (as Narendra Jadhav suggested):

listConfig: {
    ...
    listeners: {
        afterrender: function(picker) {
            picker.ownerCmp.selAllBtn.finishRender();
        }
    }
},
Alexander
  • 19,906
  • 19
  • 75
  • 162