We launched new forums in March 2019—join us there. In a hurry for help with your website? Get Help Now!
    • 38878
    • 255 Posts
    Yet another question. I have trolled the web for hours looking for a description or example on how to populate the selected values into a superboxselect in my update form. In my previous posts I worked through creating and updating the mapped data I now need to populate that data for update. The closest thing I could find was in this thread https://forums.modx.com/thread/79754/cmp-superboxselector#dis-post-443020 but I see nothing about rendering the selected values back. My record data looks like this. The categories data is what I need to render (as selected):
    {
        "id": 27,
        "title": "Mike's Biatch",
        "location": "Wherever I am",
        "company": 2,
        "type": 6,
        "source": 2,
        "description": "Yeah you know it. ",
        "applylink": "1",
        "expireson": "2015-12-25 00:00:00",
        "active": 1,
        "featured": 1,
        "filled": 0,
        "createdon": "2015-10-29 00:00:00",
        "categories": [
            "{ 'id' : 1, 'name' : Contract }",
            "{ 'id' : 3, 'name' : IT }",
            "{ 'id' : 2, 'name' : Federal }"
        ]
    }

    The store I am loading with the category options:
    Recroot.combo.Categories = function(config) {
        config = config || {};
        Ext.applyIf(config,{
            xtype:'superboxselect'
            ,triggerAction: 'all'
            ,extraItemCls: 'x-tag'
            ,mode: 'remote'
            ,forceSelection: true
            ,lazyRender: true
            ,editable : true
            ,valueField: 'id'
            ,displayField: 'name'
            ,store: new Ext.data.JsonStore({
                idProperty: 'id',
                autoLoad: true,
                root: 'results',
                fields: ['id', 'name'],
                url: Recroot.config.connectorUrl,
                baseParams: { 
                    action: 'mgr/category/getList'
                },listeners: {
                    'load': {fn:function(store, records, options ) {
                        this.hiddenName = 'categories';
                    }
                },scope : this
            }
            })
        })
        Recroot.combo.Categories.superclass.constructor.call(this,config);
    };
    Ext.extend(Recroot.combo.Categories, Ext.ux.form.SuperBoxSelect);
    Ext.reg('Categories-combo', Recroot.combo.Categories);

    And the field in my update form:
    { xtype: 'Categories-combo'
                ,fieldLabel:_('recroot.categoriess')
                ,name: 'categories'
                ,hiddenName: 'categories'
                ,valueField: 'id'
                ,displayField: 'name'
                ,multiSelect: true
                ,mode: 'remote'
                ,anchor: '95%'
    }

    The dropdown with the categories renders fine. And the selected data is being returned from my getlist processor. How do I jam those selected values into the visible field? I cant find any examples of this, not even the extjs forums.

    Any pointers? [ed. note: harveyev last edited this post 10 years, 11 months ago.]
      • 38878
      • 255 Posts
      *Bump* Anyone?
        • 51346
        • 1 Posts
        Change your grid getlist.class.php processor(I assume you are editing form a grid) to return a categories array of the ids to render into the form.
        "categories": [1,2,3]


        Use that dataIndex from the column as the name and hiddenName of the form field.
        ,{
          header: _('categories.column.header')
          ,hidden: false
          ,dataIndex: 'categories'
          ,width: 200
        }


        Add '[ ]' to the form hiddenName field so extjs knows it is an array of values.
        {
          xtype: 'Categories-combo'
          ,fieldLabel: _('categories.super.box.select.form.field')
          ,name: 'categories'
          ,hiddenName: 'categories[]'
          ,anchor: '100%'
        }


        Modify Categories-combo mode to local, add typeAhead as true, drop idProperty in the store, add id as categories-super-box-select-store in the store, change the baseParams action to mgr/category/getsimplelist, drop the listeners in the store, drop the scope in the store.
        Recroot.combo.Categories = function(config) {
            config = config || {};
            Ext.applyIf(config,{
                xtype:'superboxselect'
                ,triggerAction: 'all'
                ,extraItemCls: 'x-tag'
                ,mode: 'local'
                ,forceSelection: true
                ,lazyRender: true
                ,editable : true
                ,valueField: 'id'
                ,displayField: 'name'
                ,typeAhead:true
                ,store: new Ext.data.JsonStore({
                    id: 'categories-super-box-select-store',
                    autoLoad: true,
                    root: 'results',
                    fields: ['id', 'name'],
                    url: Recroot.config.connectorUrl,
                    baseParams: { 
                        action: 'mgr/category/getsimplelist'
                    }
                }
                })
            })
            Recroot.combo.Categories.superclass.constructor.call(this,config);
        };
        Ext.extend(Recroot.combo.Categories, Ext.ux.form.SuperBoxSelect);
        Ext.reg('Categories-combo', Recroot.combo.Categories);


        Make a new processor mgr/category/getsimplelist
        <?php
        class CategoryGetSimpleListProcessor extends modObjectGetListProcessor {
            public $classKey = 'Category';
            public $languageTopics = array('recroot:default');
            public $defaultSortField = 'id';
            public $defaultSortDirection = 'ASC';
            public $objectType = 'recroot.category';
        
            public function beforeQuery() {
                // property needs to be set here so it isn't overridden
                // forget where I came across this in github but the processor will return an empty array without it
                $this->setProperty('limit', 0);
                return true;
            }
            
            // only used if typeahead is true
            public function afterIteration(array $list){
                // toss any data points that don't match the query
                if(!empty($_POST['query'])){
                    $selections = array();
                    $match = $_POST['query'];
                    foreach($list as $item){
                        // assumed that there is a column 'name'
                        $subject = $item['name'];
                        $pattern = '/^'.$match.'/i';
                        if(preg_match($pattern, $subject) === 1){
                            $selections[] = $item;
                        };
                    }
                    return $selections;
                }
                else{
                    return $list;
                }
        
            }
        }
        return 'CategoryGetSimpleListProcessor';


        At this point you can test the cmp, but nothing will show up in the super box select the first time. Close the update window, open it back up and you should have the pre-selected values appear as removable pills.

        I can't give you a good answer as to why it fails on the first load, but there is a dirty workaround.

        When you extend the grid to add in menu items and action; modify the update action to the following.
        ,updateCategoryItem: function(btn,e) {
                this.updateCategoryItemWindow.setValues(this.menu.record);
                this.updateCategoryItemWindow.show(e.target);
                var that = this;
                    var simpleCategoryStorePoll = setInterval(function(){
                        
                        if(typeof(Ext.StoreMgr.lookup("categories-super-box-select-store")) === undefined){
                        }
                        else{
                            that.updateCategoryItemWindow.setValues(that.menu.record);
                            clearInterval(simpleCategoryStorePoll);
                        }
                    }, 50);
            }

        This forces Extjs to poll the store every 50 ms until it returns actual data that can be associated with the record ids.

        Add a new action to the grid called load stores that creates the category update window with no record.
        loadStores: function(){
                if (!this.updateCategoryItemWindow) {
                    this.updateCategoryItemWindow = MODx.load({
                        xtype: 'events-window-schedule-update'
                        ,listeners: {
                            'success': {fn:this.refresh,scope:this}
                        }
                    });
                }
            }


        Fire the loadStores action from the grid listeners.
        ,listeners :{
                    'beforerender': {fn:this.loadStores,scope:this}
                }


        Your super box select should now pre-populate on the first update window show event and have type ahead support to boot.

        Looking at this makes me cringe, this is not good for a production enviroment. Try digging through the core processors or a popular cmp that uses superbox select(migx is my favorite for development reference).

        example https://gist.github.com/mscalf/bf2e0779005072c3f494

        https://www.sofasurfer.org/blog//2011/11/21/modx-superboxselect-for-dummies/ uses this method as an example but I can't load that site ATM.

          • 38878
          • 255 Posts
          Thanks Koffeebase! I'm not editing the classes from the grid, just in the edit form. But you've given me a ton to go on so I think I'll give it a whirl. I appreciate the time you took to write this. I'll let you know how it goes.