Tuesday, 2 July 2019

Ext JS TAGFIELD for modern Toolkit

Upto now Extjs 6 sencha is not providing Tagfield for modern toolkit.
This kind of component we can use many places in current mobile apps based on client requirements. So i implemented the tagfield using picker and working as expected.

Preview:



Code snippet:

Ext.define('Ext.field.TagField', {
    extend: 'Ext.field.Picker',
    xtype: 'tagfield',
    requires: [
        'Ext.picker.Picker'
    ],
    config: {
        store: null,
        displayField: 'text',
        valueField: 'id',
        picker: 'floated',
        floatedPicker: {
            xtype: 'list',
            selectable: 'multi'
        },
        selected: {}
    },

    onSelect(t, recs) {
        let i = 0,
            len = recs.length;
        if (!this._selected) {
            this._selected = {};
        }
        while (i < len) {

            this._selected[recs[i].get(this.getValueField())] = recs[i];
            this.addTag(recs[i]);
            i++;
        }
    },

    onDeselect(t, recs) {
        let i = 0,
            len = recs.length;
        while (i < len) {
            delete this._selected[recs[i].get(this.getValueField())];
            this.removeTag(recs[i]);
            i++;
        }

    },

    addTag(tag) {
        
        var dispFld = this.getDisplayField();
        var elId = this.id + '-tagId-' + tag.internalId;
        let el = document.createElement('span');
        el.id = elId;
        el.innerHTML = `${tag.get( dispFld )} <span style="margin-left: 2px; color: red;" class="x-fa fa-times-circle" aria-hidden="true">&nbsp;</span>`;
        el.style.padding = '4px';
        el.style.margin = '4px';
        el.style.cursor = 'default';
        el.style.backgroundColor = '#1E90FF';
        el.style.borderRadius = '3px';
        if (tag.tagCls) {
            el.classList.add(tag.tagCls);
        }

        el.setAttribute('tagFieldSpan', true);

        el.querySelector('span').addEventListener('click', function () {
            this.getPicker().onItemDeselect([tag]);
            this.getPicker().setItemSelection([tag], false);
        }.bind(this));

        this.beforeInputElement.append(el);
        this.beforeInputElement.setStyle({
            marginRight: '10px',
            flexWrap: 'wrap'
        });

        let storedValues = this.getValue();
        this.fireEvent('change', this, storedValues, this._selected);
        storedValues = null;
    },

    removeTag(tag) {
        
        let removed = tag.get(this.getValueField());

        let el = this.beforeInputElement.down(`#${this.id}-tagId-${tag.internalId}`);
        if (el) {
            el.destroy();
        }

        if (!this.expanded) {
            this.syncLabelPlaceholder(true);
        }

        let storedValues = this.getValue();
        this.fireEvent('change', this, storedValues, this._selected, removed);
        storedValues = null;
        removed = null;
    },
    createFloatedPicker() {
        
        const me = this;
        let result = Ext.merge({
            ownerCmp: me,
            store: me.getStore(),
            itemTpl: '{name}',
            listeners: {
                select: {
                    fn: me.onSelect,
                    scope: me
                },
                deselect: {
                    fn: me.onDeselect,
                    scope: me
                }
            }
        }, me.getFloatedPicker());
        return result;
    },

    getValue() {
        
        var keys = Object.keys(this._selected),
            i = 0,
            len = keys.length,
            values = [];

        while (i < len) {
            values.push(this._selected[keys[i]].get(this.getValueField()));
            i++;
        }

        return values;
    },

    setValue(v) {
        
        let selection = [];

        if (!(v instanceof Array)) {
            v = [v];
        }

        let i = 0,
            len = v.length,
            store = this.getPicker().getStore(),
            f, me = this;

        if (!store) {
            return false;
        }

        if (!store.isLoaded()) {
            store.addListener('load', () => {
                me.setValue(v);
            });
            return false;
        }

        while (i < len) {
            f = store.getAt(store.findExact(this.getValueField(), v[i]));
            if (f) {
                selection.push(f);
            }
            i++;
        }

        if (selection.length) {
            this.getPicker().select(selection);
        }

        if (!this.expanded) {
            this.syncLabelPlaceholder(true);
        }
    },

    privates: {
        syncLabelPlaceholder: function (val) {
            let inside;
            this._animPlaceholderLabel = val;
            if (this.rendered) {
                if (Object.keys(this._selected).length > 0) {
                    inside = false;
                } else {
                    inside = !this.hasFocus || this.getDisabled() || this.getReadOnly();
                }
                this.setLabelInPlaceholder(inside);
            }

            this._animPlaceholderLabel = false;
        },
    },

    isInputField: false,
    isSelectField: true
});

Ext.application({
    name: 'Fiddle',
    launch: function () {

        Ext.define('Fiddle.view.MyPanel', {
            extend: 'Ext.panel.Panel',
            alias: 'TestPanelDataBinding',
            viewModel: {
                data: {
                    fName: 'HariKrishna Bura'
                }
            },
            width: 400,
            height: 300,
            title: 'Form data',
            items: [{
                xtype: 'textfield',
                bind: '{fName}',
                width: 300,
                label: 'Name'
            }, {
                xtype: 'tagfield',
                multiSelect: true,
                displayField: 'name',
                valueField: 'id',
                label: 'tag Field',
                store: Ext.create('Ext.data.Store', {
                    data: [{
                        id: 1,
                        name: 'Hyderabad'
                    }, {
                        id: 2,
                        name: 'Bengaluru'
                    }, {
                        id: 3,
                        name: 'Chennai'
                    }]
                })
            }]

        });
        /*
        tag or checkbox
        */
        var pnl = Ext.create('Fiddle.view.MyPanel', {
            fullscreen: true
        });
    }

});
 

You can access my fiddler for reference:

https://fiddle.sencha.com/#view/editor&fiddle/2sdu




1 comment: