1. #111
    Sencha User Greffin's Avatar
    Join Date
    Sep 2009
    Location
    Haugesund, Norway
    Posts
    25
    Vote Rating
    0
    Greffin is on a distinguished road

      0  

    Default


    Quote Originally Posted by mysticav View Post
    I've read that Ext 3.1 has made some improvements to CheckboxColumnModel

    Does anybody knows if these changes will impact in this plugin ?

    Have you tested on 3.1 ?

    Thanks.
    I've tested with 3.1, and found that this plugin will reverse the data from the store. I.e if the dataset contains the following:
    {"CHECKED": "false"} the checkbox will be checked.
    {"CHECKED": "true"} the checkbox will be unchecked.

    This is because the CHECKED item is NOT a boolean, even though the Field is defined of type 'boolean'. I do not know if this is a bug in Ext or this plugin, but I've made the following changes which will provide the same funcionality as before on similar datasets (I wont post the entire plugin anew. Just my changes):

    Insert before the initEvents function (Line 67):
    Code:
    parseBoolean : function(value){
      if (Ext.isDefined(value) && Ext.isString(value)) {
        return (value.toLowerCase() == 'true' ? true:false);
      }
      return value;
    },
    Replace the dataIndexValue in the on store load event handler (will be line 167):
    Code:
    var dataIndexValue = this.parseBoolean(p.data.items[i].data[dataIndex]); // the value of the dataIndex for each row
    Replace the isChecked in the onMouseDown function (will be line 379):
    Code:
    var isChecked = this.parseBoolean(record.data[this.dataIndex]);
    And the most important part, insert in the renderer function (will be line 443):
    Code:
    v = this.parseBoolean(v);
    I hope this will save some headache for others.

  2. #112
    Ext User Coen's Avatar
    Join Date
    Jan 2010
    Posts
    5
    Vote Rating
    0
    Coen is on a distinguished road

      0  

    Default


    Since the update to 3.1 I've experienced a different issue with this model. Upon closing a tab window which contained a Grid with this model, FireBug reported to me the following error:

    Code:
    n is undefined in ext-all.js (line 7)
    Or,

    Code:
    l is undefined in ext-all-debug.js (line 1537)
    What I found out is that, when registering for the view's "columnmove" event in initEvent's grid render event handler, the handler is set to this.onColumnMove, which does not exist. I'm not sure if it has ever existed, but commenting out this line fixed the error and did not cause any side effects.

    For me, this is line 87, but I've already made several different fixes (boolean render, header id) so it may differ to your line numbering.

  3. #113
    Sencha User
    Join Date
    Feb 2010
    Posts
    7
    Vote Rating
    0
    kdeelstra is on a distinguished road

      0  

    Default works in Ext js 3.1?

    works in Ext js 3.1?


    Will this work in works in Ext js 3.1? Do you have live example?

  4. #114
    Ext JS Premium Member NoahK17's Avatar
    Join Date
    Apr 2008
    Location
    Atlanta, GA
    Posts
    518
    Vote Rating
    1
    NoahK17 is on a distinguished road

      0  

    Default


    Quote Originally Posted by kdeelstra View Post
    Will this work in works in Ext js 3.1? Do you have live example?
    I honestly haven't touched this code since the summer of 2007. I've heard mixed reports about it working with 3.1, check back a few posts and see what people say. I also received a PM linking me to this post which talks about 3.1 compatibility with the SmartCheckboxSelectionModel: http://www.extjs.com/forum/showthread.php?t=88754 (may or may not be useful).

    Long story short, when or if I find the need with my current job to code something that would require the SmartCheckboxSelectionModel, I will take the code and update it to work with 3.1 fully.
    Noah
    Senior Web Developer
    NBA.com

  5. #115
    Ext JS Premium Member NoahK17's Avatar
    Join Date
    Apr 2008
    Location
    Atlanta, GA
    Posts
    518
    Vote Rating
    1
    NoahK17 is on a distinguished road

      0  

    Default


    Quote Originally Posted by Coen View Post
    Since the update to 3.1 I've experienced a different issue with this model. Upon closing a tab window which contained a Grid with this model, FireBug reported to me the following error:

    Code:
    n is undefined in ext-all.js (line 7)
    Or,

    Code:
    l is undefined in ext-all-debug.js (line 1537)
    What I found out is that, when registering for the view's "columnmove" event in initEvent's grid render event handler, the handler is set to this.onColumnMove, which does not exist. I'm not sure if it has ever existed, but commenting out this line fixed the error and did not cause any side effects.

    For me, this is line 87, but I've already made several different fixes (boolean render, header id) so it may differ to your line numbering.
    Coen, do you mind posting your full SmartCheckboxSelectionModel code changes here so I can update the original thread with a working 3.1 version?
    Noah
    Senior Web Developer
    NBA.com

  6. #116
    Ext User Coen's Avatar
    Join Date
    Jan 2010
    Posts
    5
    Vote Rating
    0
    Coen is on a distinguished road

      0  

    Default


    Sure, no problem!

    I must add however that my use of your SmartCheckboxSelectionModel is limited to usage with email = true only and I have detached it from working with the StateManager - I use my own. Therefor I cannot guarantee it's perfectly compatible with 3.1.

    Unfortunately the project I work with is not public so I do not have a live version for you to try, I'm sorry.

    Usage:
    Code:
    var checkboxModel = new Ext.grid.SmartCheckboxSelectionModel({
            dataIndex: 'Selected',
            email: true
    });
    
    var grid = new Ext.grid.EditorGridPanel({
            selModel: checkboxModel,
            columns: [
                     checkboxModel,
                     ...
            ],
            ...
    });
    Code:
    Code:
    /**
    * @class Ext.grid.SmartCheckboxSelectionModel
    * @extends Ext.grid.RowSelectionModel
    *
    * A custom selection model that renders a column of checkboxes that can be toggled to select or deselect rows.
    * By passing in a dataIndex and a store, it can pre-check (and select) rows after it renders.
    * Included are all the standard navigation options of a RowSelectionModel, including Up/Down arrow keyMaps and Ctrl/Shift selections.
    *
    * @param         (object)         config         The configuration options, as highlighted below
    * @param        (string)        dataIndex    The field that contains the boolen true/false value for checked/selected rows        
    *
    * @copyright    June 4, 2008    <last updated: July 1, 2008>
    * @author        Noah Kronemeyer    <nkronemeyer@therubicongroup.com>
    * @version        1.7
    */
    Ext.grid.SmartCheckboxSelectionModel = Ext.extend(Ext.grid.RowSelectionModel, {
        constructor: function(){
            this.header = '<div id="'+ (this.headerId = Ext.id()) +'" class="x-grid3-hd-checker"> </div>';
            Ext.grid.SmartCheckboxSelectionModel.superclass.constructor.apply(this,arguments);
        },
        /**
        * @header (string)        Any valid text or HTML fragment to display in the header cell for the checkbox column
        *                         (defaults to '<div id="x-grid3-hd-checker" class="x-grid3-hd-checker"> </div>').  The default CSS
        *                        class of 'x-grid3-hd-checker' displays a checkbox in the header and provides support
        *                        for automatic check all/none behavior on header click. This string can be replaced by
        *                        any valid HTML fragment, but if you use a simple text string (e.g., 'Select Rows'), you must include it
        *                        in the following format: <div id="x-grid3-hd-checker">&nbsp;Simple String</div>, in addition
        *                         the automatic check all/none behavior will only work if the 'x-grid3-hd-checker' class is supplied.
        */
        //header: '<div id="'+this.headerId+'" class="x-grid3-hd-checker"> </div>',
        /**
        * @width        (int)    The default width in pixels of the checkbox column (defaults to 20).
        */
        width: 20,
        /**
        * @sortable    (bool)    Set to true if you want the checkbox column to be sortable.
        */
        sortable: false,
        /**
        * @email        (bool)    Will mimic email client functionality by separating out the selection of rows
        *                        with the checking of rows, similar to how Yahoo! or Gmail works. One could then
        *                        apply different actions on checked rows vs. selected rows.
        *                        Defaults to false. 
        */
        email: false,
        /**
        * @excel        (bool)    Mimics excel functionality when clicking on rows or checkboxes. If set to true,
        *                        all other rows will be deselected and unchecked except the row you most recently
        *                        clicked. If set to false, all previous selections will remain selected and/or checked
        *                        as you click around the grid (as if you were holding down CTRL and clicking).
        *                        Defaults to false. 
        */
        excel: true,
        
        toggleSelect: true,
    
        /**
        * @alwaysSelectOnCheck        
        *                (bool)    If set to true, clicking a checkbox will always select the row, working in conjunction
        *                        with the email option.
        *                        Defaults to false.
        *
        */
        alwaysSelectOnCheck: false,
    
        // private
        menuDisabled: true,
        fixed: true,
        id: 'checker',
        dataIndex: '', // Define the dataIndex when you construct the selectionModel, not here
    
        // private
        parseBoolean : function(value){
          if (Ext.isDefined(value) && Ext.isString(value)) {
            return (value.toLowerCase() == 'true' ? true:false);
          }
          return value;
        },
    
        // private
        initEvents: function() {
            // Call the parent
            Ext.grid.SmartCheckboxSelectionModel.superclass.initEvents.call(this);
            // Assign the handlers for the mousedown events
            this.grid.on('render', function() {
                var view = this.grid.getView();
                //view.on('columnmove', this.onColumnMove, this);
                view.mainBody.on('mousedown', this.onMouseDown, this);
                Ext.fly(view.innerHd).on('mousedown', this.onHdMouseDown, this);
            }, this);
            // Disable the rowNav created in our parent object, otherwise pressing DOWN will go down two rows!
            this.rowNav.disable();
            // Create our new rowNav that controls checkboxes as well
            this.rowNav2 = new Ext.KeyNav(this.grid.getGridEl(), {
                "up": function(e) {
                    if (!e.shiftKey) {
                        if (!this.email) { this.selectPreviousChecked(e.shiftKey); }
                        if (this.email) { this.selectPrevious(e.shiftKey); }
                    }
                    else if (this.last !== false && this.lastActive !== false) {
                        var last = this.last;
                        if (!this.email) { this.selectRangeChecked(this.last, this.lastActive - 1); }
                        if (this.email) { this.selectRange(this.last, this.lastActive - 1); }
                        this.grid.getView().focusRow(this.lastActive);
                        if (last !== false) {
                            this.last = last;
                        }
                    }
                    else {
                        this.selectFirstRow();
                        if (!this.email) { this.toggleChecked(0, true); }
                    }
                },
                "down": function(e) {
                    if (!e.shiftKey) {
                        if (!this.email) { this.selectNextChecked(e.shiftKey); }
                        if (this.email) { this.selectNext(e.shiftKey); }
                    }
                    else if (this.last !== false && this.lastActive !== false) {
                        var last = this.last;
                        if (!this.email) { this.selectRangeChecked(this.last, this.lastActive + 1); }
                        if (this.email) { this.selectRange(this.last, this.lastActive + 1); }
                        this.grid.getView().focusRow(this.lastActive, true);
                        if (last !== false) {
                            this.last = last;
                        }
                    }
                    else {
                        this.selectFirstRow();
                        if (!this.email) { this.toggleChecked(0, true); }
                    }
                },
                scope: this
            });
            // Listen for the movement of the columns  
            this.grid.on('columnmove', function(p) {
                var t = Ext.get(this.headerId);
                if (t != null) {
                    if (t.dom.className != 'x-grid3-hd-checker') {
                        Ext.fly(t.dom.parentNode).removeClass('x-grid3-hd-checker');
                    }
                }
            });
            // If we sent a store to the selModel, auto-select rows based on dataIndex
            if (this.grid.store) {
                this.grid.store.on('load', function(p) {
                    // This block of code checks the status of the checkbox header, 
                    // and if checked, will check all other checkboxes (but not on the initial load)
                    var t = Ext.get(this.headerId);
                    if (t != null) {
                        if (t.dom.className == 'x-grid3-hd-checker' && Ext.state.Manager.loaded) {
                            var hd = Ext.fly(t.dom.parentNode);
                            var isChecked = hd.hasClass('x-grid3-hd-checker-on');
                            if (isChecked) {
                                hd.addClass('x-grid3-hd-checker-on');
                                if (!this.email) { this.selectAll(); }
                                this.selectAllChecked(true);
                            }
                        }
                        else {
                            Ext.fly(t.dom.parentNode).removeClass('x-grid3-hd-checker');
                        }
                    }
    
                    // This block of code will pre-select checkboxes based on the dataIndex supplied,
                    // but only on the initial load.
                    var dataIndex = this.grid.getSelectionModel().dataIndex; // the dataIndex for the selectionModel
                    if(this.grid.store == null) return;
                    var count = this.grid.store.getCount();
                    for (var i = 0, len = count; i < len; i++) {
                        var dataIndexValue = this.parseBoolean(p.data.items[i].data[dataIndex]); // the value of the dataIndex for each row
                        var isSelected = this.isSelected(i);
                        if ((dataIndexValue == true || isSelected) && !Ext.state.Manager.loaded) {
                            // This code will only run the first time a grid is loaded 
                            // Make sure that any "checked" rows are also selected
                            if (!this.email || this.alwaysSelectOnCheck) { this.grid.getSelectionModel().selectRow(i, true); }
                        }
                        else if (isSelected) {
                            // Let the state.Manager check the correct rows now
                            if (!this.email) { this.toggleChecked(i, true); }
                        }
                        else {
                            // Uncheck everything else
                            if (!this.email) { this.toggleChecked(i, false); }
                        }
                    }
                }, this);
            }
        },
    
        /**
        * private function that controls the checkboxes
        *
        * @param    (int)    rowIndex    the row you want to toggle
        * @param    (bool)    c            optional flag set to either true (to check) or false (to uncheck)
        *                                if no second param, the checkbox will toggle itself 
        */
        toggleChecked: function(rowIndex, c) {
            if (this.locked) return;
            var record = this.grid.store.getAt(rowIndex);
            if (c === true) {
                // Check
                record.set(this.dataIndex, true);
            }
            else if (c === false) {
                // Uncheck
                record.set(this.dataIndex, false);
            }
            else {
                // Toggle checked / unchecked
                record.set(this.dataIndex, !record.data[this.dataIndex]);
            }
            this.fireEvent("rowcheckchanged", this, rowIndex, c, record);
        },
    
        /**
        * private functions that toggles all checkboxes on or off depending on param
        *
        * @param    (bool)    c        true to check all checkboxes, false to uncheck all checkboxes        
        * @param    (int)    e        (optional) if an exception is given, all rows will be checked/unchecked except this row        
        */
        selectAllChecked: function(c, e) {
            if (this.locked) return;
            var count = this.grid.store.getCount();
            for (var i = 0, len = count; i < len; i++) {
                if (c) {
                    if (i !== e) {
                        this.toggleChecked(i, true);
                    }
                }
                else {
                    if (i !== e) {
                        this.toggleChecked(i, false);
                    }
                }
            }
        },
    
        /**
        * private function that clears all checkboxes
        * specifically used to deal with shift+arrow keys,
        * but can also be called with fast param to quickly uncheck everything
        *
        * @param    (bool)    fast    true to quickly deselect everything with no exceptions
        */
        clearChecked: function(fast) {
            if (this.locked) return;
            if (fast !== true) {
                var count = this.grid.store.getCount();
                for (var i = 0, len = count; i < len; i++) {
                    var isSelected = this.isSelected(i);
                    if (!isSelected) {
                        this.toggleChecked(i, false);
                    }
                }
            }
            else {
                // Quick and dirty method to uncheck everything
                this.selectAllChecked(false);
            }
            this.last = false;
        },
    
        /**
        * private function used in conjuction with the shift key for checking multiple rows at once
        */
        selectRangeChecked: function(startRow, endRow, keepExisting) {
            if (this.locked) return;
            if (!keepExisting) {
                if (!this.email || this.alwaysSelectOnCheck) { this.clearSelections(); }
                this.clearChecked();
            }
            if (startRow <= endRow) {
                for (var i = startRow; i <= endRow; i++) {
                    if (this.grid.store.getAt(i)) {
                        this.toggleChecked(i, true);
                        if (!this.email || this.alwaysSelectOnCheck) { this.selectRow(i, true); }
                    }
                }
            }
            else {
                for (var i = startRow; i >= endRow; i--) {
                    if (this.grid.store.getAt(i)) {
                        this.toggleChecked(i, true);
                        if (!this.email || this.alwaysSelectOnCheck) { this.selectRow(i, true); }
                    }
                }
            }
        },
        /**
        * private function that is used with the UP arrow keyMap
        */
        selectPreviousChecked: function(keepExisting) {
            if (this.hasPrevious()) {
                // Select the next row
                this.selectRow(this.last - 1, keepExisting);
                // Set the focus
                this.grid.getView().focusRow(this.last);
                if (!this.email) {
                    // Check the current (selected) row
                    this.toggleChecked(this.last, true);
                    // Uncheck all other rows
                    this.selectAllChecked(false, this.last);
                }
                return true;
            }
            return false;
        },
        /**
        * private function that is used with the DOWN arrow keyMap
        */
        selectNextChecked: function(keepExisting) {
            if (this.hasNext()) {
                // Select the next row
                if (!this.email) { this.selectRow(this.last + 1, keepExisting); }
                // Set the focus
                this.grid.getView().focusRow(this.last);
                if (!this.email) {
                    // Check the current (selected) row
                    this.toggleChecked(this.last, true);
                    // Uncheck all other rows
                    this.selectAllChecked(false, this.last);
                }
                return true;
            }
            return false;
        },
    
        /**
        * private function that executes when you click on any row
        * will keep other row selections active as you click around
        */
        handleMouseDown: function(g, rowIndex, e) {
            var t = e.getTarget('.ux-row-action-item');
            if (!t) {
                if (e.button !== 0 || this.isLocked()) {
                    return;
                };
                var view = this.grid.getView();
                var record = this.grid.store.getAt(rowIndex);
                if (e.shiftKey && this.last !== false) {
                    var last = this.last;
                    this.selectRange(last, rowIndex, e.ctrlKey);
                    if (!this.email) { this.selectRangeChecked(last, rowIndex, e.ctrlKey); }
                    this.last = last; // reset the last
                    view.focusRow(rowIndex);
                } else {
                    var isChecked = record.data[this.dataIndex];
                    var isSelected = this.isSelected(rowIndex);
    
                    if (isSelected && this.toggleSelect) {
                        this.deselectRow(rowIndex);
                        if (!this.email) { this.toggleChecked(rowIndex, false); }
                    } else {
                        if (!this.excel) {
                            this.selectRow(rowIndex, true);
                            if (!this.email) {
                                this.toggleChecked(rowIndex, true);
                            }
                        }
                        else {
                            this.selectRow(rowIndex, e.ctrlKey);
                            if (!this.email) {
                                this.selectRangeChecked(rowIndex, rowIndex, e.ctrlKey);
                            }
                        }
                        view.focusRow(rowIndex);
                    }
                }
            }
        },
        /**
        * private function restricted to execute when you click a checkbox itself
        */
        onMouseDown: function(e, t) {
            if (t.className && t.className.indexOf('x-grid3-cc-' + this.id) != -1) {
                e.stopEvent();
                // Define variables
                var view = this.grid.getView();
                var rowIndex = view.findRowIndex(t);
                var record = this.grid.store.getAt(rowIndex);
                var isSelected = this.isSelected(rowIndex);
                var isChecked = this.parseBoolean(record.data[this.dataIndex]);
                // Logic to select/de-select rows and the checkboxes
                if (!this.email || this.alwaysSelectOnCheck) {
                    if (isSelected) {
                        if (!isChecked && this.alwaysSelectOnCheck) {
                            this.toggleChecked(rowIndex, true);
                        }
                        else {
                            this.deselectRow(rowIndex);
                            this.toggleChecked(rowIndex, false);
                        }
                    }
                    else {
                        this.selectRow(rowIndex, true);
                        this.toggleChecked(rowIndex, true);
                        view.focusRow(rowIndex);
                    }
                }
                else {
                    if (isChecked) {
                        this.toggleChecked(rowIndex, false);
                    }
                    else {
                        this.toggleChecked(rowIndex, true);
                    }
                }
                view.focusRow(rowIndex);
            }
            // Load the state manager
            Ext.state.Manager.setProvider(new Ext.state.CookieProvider());
            Ext.state.Manager.loaded = true;
        },
    
    
        /**
        * private function that executes when you click the checkbox header
        */
        onHdMouseDown: function(e, t) {
            if (t.className == 'x-grid3-hd-checker') {
                e.stopEvent();
                var hd = Ext.fly(t.parentNode);
                var isChecked = hd.hasClass('x-grid3-hd-checker-on');
                if (isChecked) {
                    hd.removeClass('x-grid3-hd-checker-on');
                    if (!this.email || this.alwaysSelectOnCheck) { this.clearSelections(); }
                    this.clearChecked(true); // the true param enables fast mode
                } else {
                    hd.addClass('x-grid3-hd-checker-on');
                    if (!this.email || this.alwaysSelectOnCheck) { this.selectAll(); }
                    this.selectAllChecked(true);
                }
            }
            // Load the state manager
            Ext.state.Manager.setProvider(new Ext.state.CookieProvider());
            Ext.state.Manager.loaded = true;
        },
    
        /**
        * private function that renders the proper checkbox based on your dataIndex variable
        *
        * @param    (varchar)    v        the dataIndex passed into the selectionModel that contains whether a row is checked by default or not
        */
        renderer: function(v, p, record) {
            v = this.parseBoolean(v);
            p.css += ' x-grid3-check-col-td';
            return '<div class="x-grid3-check-col' + (v ? '-on' : '') + ' x-grid3-cc-' + this.id + '"> </div>';
        }
    });
    Credits also to earlier posters in this thread!

  7. #117
    Ext JS Premium Member mcouillard's Avatar
    Join Date
    Jun 2008
    Location
    Bucks County, PA
    Posts
    104
    Vote Rating
    9
    mcouillard will become famous soon enough

      0  

    Default 3.1.1 OK

    3.1.1 OK


    Working fine here on 3.1.1 without any changes to your plugin required. Thanks again!

    (usage: just a simple non-paged grid of checkboxes down the left)

  8. #118
    Ext JS Premium Member NoahK17's Avatar
    Join Date
    Apr 2008
    Location
    Atlanta, GA
    Posts
    518
    Vote Rating
    1
    NoahK17 is on a distinguished road

      0  

    Default


    Quote Originally Posted by mcouillard View Post
    Working fine here on 3.1.1 without any changes to your plugin required. Thanks again!

    (usage: just a simple non-paged grid of checkboxes down the left)
    Oh, well that's great news. Thanks MC!
    Noah
    Senior Web Developer
    NBA.com

  9. #119
    Sencha User
    Join Date
    Mar 2007
    Posts
    218
    Vote Rating
    0
    alien3d is on a distinguished road

      0  

    Default


    working fine in extjs 3.11 great more better then checkColumn.

  10. #120
    Sencha User steffenk's Avatar
    Join Date
    Jul 2007
    Location
    Haan, Germany
    Posts
    2,664
    Vote Rating
    7
    steffenk has a spectacular aura about steffenk has a spectacular aura about steffenk has a spectacular aura about

      0  

    Default


    Thanks for this excellent extension. I use it with 3.1.1 and it works fine. Reading selected from store is one of the biggest highlight of this extension. You made my day!
    Attached Images
    vg Steffen
    --------------------------------------
    Release Manager of TYPO3 4.5

Similar Threads

  1. Smart tooltip
    By same66 in forum Ext 3.x: Help & Discussion
    Replies: 4
    Last Post: 24 Feb 2011, 7:02 PM
  2. Ext.each : with remove - not smart enough
    By DaveC426913 in forum Sencha Touch 1.x: Discussion
    Replies: 5
    Last Post: 30 Nov 2010, 10:36 AM
  3. Is smart rendering possible in grid???
    By jeff77 in forum Ext 3.x: Help & Discussion
    Replies: 2
    Last Post: 10 Sep 2010, 12:03 AM
  4. Smart Ext toolbar
    By tinnt in forum Ext 2.x: Help & Discussion
    Replies: 4
    Last Post: 20 Nov 2008, 7:04 PM
  5. GridPanel - smart rendering
    By embolooloo in forum Ext 2.x: Help & Discussion
    Replies: 4
    Last Post: 8 Oct 2007, 7:57 PM

Thread Participants: 62