Thank you for reporting this bug. We will make it our priority to review this report.
  1. #11
    Sencha User
    Join Date
    Jun 2009
    Posts
    750
    Vote Rating
    0
    meroy is on a distinguished road

      0  

    Default


    Yes, this has been fixed in SVN by applying Condor's fix. Thanks.

  2. #12
    Ext JS Premium Member
    Join Date
    Jan 2008
    Posts
    315
    Vote Rating
    0
    josh803316 is on a distinguished road

      0  

    Default


    I just got the latest SVN RowEditor.js and it still appears to be broken. I have 3 columns in my rowEditor and when I edit the 2nd column with new text It shows me that the oldValue = newValue, and therefore the event doesn't fire because hasChange = false. The text area started blank and I added some text but it wasn't recognized as a change. It seems the oldValue isn't correct

    Code:
    if(!Ext.isEmpty(dindex)){
                        var oldValue = r.data[dindex],
                            value = this.postEditValue(fields[i].getValue(), oldValue, r, dindex);
                            console.info(oldValue,value,hasChange);
                        if(String(oldValue) !== String(value)){
                            changes[dindex] = value;
                            hasChange = true;
                        }
                    }

  3. #13
    Sencha User
    Join Date
    May 2009
    Posts
    1
    Vote Rating
    0
    alixchap is on a distinguished road

      0  

    Default A workaround for this error

    A workaround for this error


    I know this is an old thread but I will share my workaround in case someone finds it useful.

    In order to stop losing the old value I created a new attribute in the RowEditor object to save it (this.old_record). This variable is filled in the “startEditing” event but it does not copy the object by reference. It loops the record in order to copy only the values.
    It seems that the values were overwritten at some point in the code by the reference they kept.

    Here is the code:
    Code:
    Ext.ns('Ext.ux.grid');
    
    
    /**
     * @class Ext.ux.grid.RowEditor
     * @extends Ext.Panel
     * Plugin (ptype = 'roweditor') that adds the ability to rapidly edit full rows in a grid.
     * A validation mode may be enabled which uses AnchorTips to notify the user of all
     * validation errors at once.
     *
     * @ptype roweditor
     */
    Ext.ux.grid.RowEditor = Ext.extend(Ext.Panel, {
        floating: true,
        shadow: false,
        layout: 'hbox',
        cls: 'x-small-editor',
        buttonAlign: 'center',
        baseCls: 'x-row-editor',
        elements: 'header,footer,body',
        frameWidth: 5,
        buttonPad: 3,
        clicksToEdit: 'auto',
        monitorValid: true,
        focusDelay: 250,
        errorSummary: true,
    
    
        saveText: 'Save',
        cancelText: 'Cancel',
        commitChangesText: 'You need to commit or cancel your changes',
        errorText: 'Errors',
    
    
        defaults: {
            normalWidth: true
        },
    
    
        initComponent: function(){
            Ext.ux.grid.RowEditor.superclass.initComponent.call(this);
            this.addEvents(
                /**
                 * @event beforeedit
                 * Fired before the row editor is activated.
                 * If the listener returns <tt>false</tt> the editor will not be activated.
                 * @param {Ext.ux.grid.RowEditor} roweditor This object
                 * @param {Number} rowIndex The rowIndex of the row just edited
                 */
                'beforeedit',
                /**
                 * @event canceledit
                 * Fired when the editor is cancelled.
                 * @param {Ext.ux.grid.RowEditor} roweditor This object
                 * @param {Boolean} forced True if the cancel button is pressed, false is the editor was invalid.
                 */
                'canceledit',
                /**
                 * @event validateedit
                 * Fired after a row is edited and passes validation.
                 * If the listener returns <tt>false</tt> changes to the record will not be set.
                 * @param {Ext.ux.grid.RowEditor} roweditor This object
                 * @param {Object} changes Object with changes made to the record.
                 * @param {Ext.data.Record} r The Record that was edited.
                 * @param {Number} rowIndex The rowIndex of the row just edited
                 */
                'validateedit',
                /**
                 * @event afteredit
                 * Fired after a row is edited and passes validation.  This event is fired
                 * after the store's update event is fired with this edit.
                 * @param {Ext.ux.grid.RowEditor} roweditor This object
                 * @param {Object} changes Object with changes made to the record.
                 * @param {Ext.data.Record} r The Record that was edited.
                 * @param {Number} rowIndex The rowIndex of the row just edited
                 */
                'afteredit'
            );
        },
    
    
        init: function(grid){
            this.grid = grid;
            this.ownerCt = grid;
            if(this.clicksToEdit === 2){
                grid.on('rowdblclick', this.onRowDblClick, this);
            }else{
                grid.on('rowclick', this.onRowClick, this);
                if(Ext.isIE){
                    grid.on('rowdblclick', this.onRowDblClick, this);
                }
            }
    
    
            // stopEditing without saving when a record is removed from Store.
            grid.getStore().on('remove', function() {
                this.stopEditing(false);
            },this);
    
    
            grid.on({
                scope: this,
                keydown: this.onGridKey,
                columnresize: this.verifyLayout,
                columnmove: this.refreshFields,
                reconfigure: this.refreshFields,
                beforedestroy : this.beforedestroy,
                destroy : this.destroy,
                bodyscroll: {
                    buffer: 250,
                    fn: this.positionButtons
                }
            });
            grid.getColumnModel().on('hiddenchange', this.verifyLayout, this, {delay:1});
            grid.getView().on('refresh', this.stopEditing.createDelegate(this, []));
        },
    
    
        beforedestroy: function() {
            this.stopMonitoring();
            this.grid.getStore().un('remove', this.onStoreRemove, this);
            this.stopEditing(false);
            Ext.destroy(this.btns, this.tooltip);
        },
    
    
        refreshFields: function(){
            this.initFields();
            this.verifyLayout();
        },
    
    
        isDirty: function(){
            var dirty;
            this.items.each(function(f){
                if(String(this.values[f.id]) !== String(f.getValue())){
                    dirty = true;
                    return false;
                }
            }, this);
            return dirty;
        },
    
    
        startEditing: function(rowIndex, doFocus){
            if(this.editing && this.isDirty()){
                this.showTooltip(this.commitChangesText);
                return;
            }
            if(Ext.isObject(rowIndex)){
                rowIndex = this.grid.getStore().indexOf(rowIndex);
            }
            if(this.fireEvent('beforeedit', this, rowIndex) !== false){
                this.editing = true;
                var newObj = {};
                var g = this.grid, view = g.getView(),
                    row = view.getRow(rowIndex);
                    record = g.store.getAt(rowIndex),
                    record_data = g.store.getAt(rowIndex).data;        
                    
                // avoid using the object by reference
                for (var key in record_data) {
                    newObj[key]=record_data[key];        
                }
                                
                this.record = record;
                this.rowIndex = rowIndex;
                this.values = {};
                this.old_record=newObj;
                
                if(!this.rendered){
                    this.render(view.getEditorParent());
                }
                var w = Ext.fly(row).getWidth();
                this.setSize(w);
                if(!this.initialized){
                    this.initFields();
                }
                var cm = g.getColumnModel(), fields = this.items.items, f, val;
                for(var i = 0, len = cm.getColumnCount(); i < len; i++){
                    val = this.preEditValue(record, cm.getDataIndex(i));
                    f = fields[i];
                    f.setValue(val);
                    this.values[f.id] = Ext.isEmpty(val) ? '' : val;
                }
                this.verifyLayout(true);
                if(!this.isVisible()){
                    this.setPagePosition(Ext.fly(row).getXY());
                } else{
                    this.el.setXY(Ext.fly(row).getXY(), {duration:0.15});
                }
                if(!this.isVisible()){
                    this.show().doLayout();
                }
                if(doFocus !== false){
                    this.doFocus.defer(this.focusDelay, this);
                }
            }
        },
    
    
        stopEditing : function(saveChanges){
            this.editing = false;
            if(!this.isVisible()){
                return;
            }
            if(saveChanges === false || !this.isValid()){
                this.hide();
                this.fireEvent('canceledit', this, saveChanges === false);
                return;
            }
            var changes = {},
                r = this.record,   
                r_old = this.old_record,
                hasChange = false,  
                cm = this.grid.colModel,
                fields = this.items.items;
            for(var i = 0, len = cm.getColumnCount(); i < len; i++){
                if(!cm.isHidden(i)){
                    var dindex = cm.getDataIndex(i);
                    if(!Ext.isEmpty(dindex)){
                        var oldValue = r_old[dindex],
                            value = this.postEditValue(fields[i].getValue(), oldValue, r, dindex);
                        if(String(oldValue) !== String(value)){
                            changes[dindex] = value;
                            hasChange = true;
                        }
                    }
                }
            }
            if(hasChange && this.fireEvent('validateedit', this, changes, r, this.rowIndex) !== false){
                r.beginEdit();
                Ext.iterate(changes, function(name, value){
                    r.set(name, value);
                });
                r.endEdit();
                this.fireEvent('afteredit', this, changes, r, this.rowIndex);
            }
            this.hide();
        },
    
    
        verifyLayout: function(force){
            if(this.el && (this.isVisible() || force === true)){
                var row = this.grid.getView().getRow(this.rowIndex);
                this.setSize(Ext.fly(row).getWidth(), Ext.isIE ? Ext.fly(row).getHeight() + 9 : undefined);
                var cm = this.grid.colModel, fields = this.items.items;
                for(var i = 0, len = cm.getColumnCount(); i < len; i++){
                    if(!cm.isHidden(i)){
                        var adjust = 0;
                        if(i === (len - 1)){
                            adjust += 3; // outer padding
                        } else{
                            adjust += 1;
                        }
                        fields[i].show();
                        fields[i].setWidth(cm.getColumnWidth(i) - adjust);
                    } else{
                        fields[i].hide();
                    }
                }
                this.doLayout();
                this.positionButtons();
            }
        },
    
    
        slideHide : function(){
            this.hide();
        },
    
    
        initFields: function(){
            var cm = this.grid.getColumnModel(), pm = Ext.layout.ContainerLayout.prototype.parseMargins;
            this.removeAll(false);
            for(var i = 0, len = cm.getColumnCount(); i < len; i++){
                var c = cm.getColumnAt(i),
                    ed = c.getEditor();
                if(!ed){
                    ed = c.displayEditor || new Ext.form.DisplayField();
                }
                if(i == 0){
                    ed.margins = pm('0 1 2 1');
                } else if(i == len - 1){
                    ed.margins = pm('0 0 2 1');
                } else{
                    if (Ext.isIE) {
                        ed.margins = pm('0 0 2 0');
                    }
                    else {
                        ed.margins = pm('0 1 2 0');
                    }
                }
                ed.setWidth(cm.getColumnWidth(i));
                ed.column = c;
                if(ed.ownerCt !== this){
                    ed.on('focus', this.ensureVisible, this);
                    ed.on('specialkey', this.onKey, this);
                }
                this.insert(i, ed);
            }
            this.initialized = true;
        },
    
    
        onKey: function(f, e){
            if(e.getKey() === e.ENTER){
                this.stopEditing(true);
                e.stopPropagation();
            }
        },
    
    
        onGridKey: function(e){
            if(e.getKey() === e.ENTER && !this.isVisible()){
                var r = this.grid.getSelectionModel().getSelected();
                if(r){
                    var index = this.grid.store.indexOf(r);
                    this.startEditing(index);
                    e.stopPropagation();
                }
            }
        },
    
    
        ensureVisible: function(editor){
            if(this.isVisible()){
                 this.grid.getView().ensureVisible(this.rowIndex, this.grid.colModel.getIndexById(editor.column.id), true);
            }
        },
    
    
        onRowClick: function(g, rowIndex, e){
            if(this.clicksToEdit == 'auto'){
                var li = this.lastClickIndex;
                this.lastClickIndex = rowIndex;
                if(li != rowIndex && !this.isVisible()){
                    return;
                }
            }
            this.startEditing(rowIndex, false);
            this.doFocus.defer(this.focusDelay, this, [e.getPoint()]);
        },
    
    
        onRowDblClick: function(g, rowIndex, e){
            this.startEditing(rowIndex, false);
            this.doFocus.defer(this.focusDelay, this, [e.getPoint()]);
        },
    
    
        onRender: function(){
            Ext.ux.grid.RowEditor.superclass.onRender.apply(this, arguments);
            this.el.swallowEvent(['keydown', 'keyup', 'keypress']);
            this.btns = new Ext.Panel({
                baseCls: 'x-plain',
                cls: 'x-btns',
                elements:'body',
                layout: 'table',
                width: (this.minButtonWidth * 2) + (this.frameWidth * 2) + (this.buttonPad * 4), // width must be specified for IE
                items: [{
                    ref: 'saveBtn',
                    itemId: 'saveBtn',
                    xtype: 'button',
                    text: this.saveText,
                    width: this.minButtonWidth,
                    handler: this.stopEditing.createDelegate(this, [true])
                }, {
                    xtype: 'button',
                    text: this.cancelText,
                    width: this.minButtonWidth,
                    handler: this.stopEditing.createDelegate(this, [false])
                }]
            });
            this.btns.render(this.bwrap);
        },
    
    
        afterRender: function(){
            Ext.ux.grid.RowEditor.superclass.afterRender.apply(this, arguments);
            this.positionButtons();
            if(this.monitorValid){
                this.startMonitoring();
            }
        },
    
    
        onShow: function(){
            if(this.monitorValid){
                this.startMonitoring();
            }
            Ext.ux.grid.RowEditor.superclass.onShow.apply(this, arguments);
        },
    
    
        onHide: function(){
            Ext.ux.grid.RowEditor.superclass.onHide.apply(this, arguments);
            this.stopMonitoring();
            this.grid.getView().focusRow(this.rowIndex);
        },
    
    
        positionButtons: function(){
            if(this.btns){
                var g = this.grid,
                    h = this.el.dom.clientHeight,
                    view = g.getView(),
                    scroll = view.scroller.dom.scrollLeft,
                    bw = this.btns.getWidth(),
                    width = Math.min(g.getWidth(), g.getColumnModel().getTotalWidth());
    
    
                this.btns.el.shift({left: (width/2)-(bw/2)+scroll, top: h - 2, stopFx: true, duration:0.2});
            }
        },
    
    
        // private
        preEditValue : function(r, field){
            var value = r.data[field];
            return this.autoEncode && typeof value === 'string' ? Ext.util.Format.htmlDecode(value) : value;
        },
    
    
        // private
        postEditValue : function(value, originalValue, r, field){
            return this.autoEncode && typeof value == 'string' ? Ext.util.Format.htmlEncode(value) : value;
        },
    
    
        doFocus: function(pt){
            if(this.isVisible()){
                var index = 0,
                    cm = this.grid.getColumnModel(),
                    c;
                if(pt){
                    index = this.getTargetColumnIndex(pt);
                }
                for(var i = index||0, len = cm.getColumnCount(); i < len; i++){
                    c = cm.getColumnAt(i);
                    if(!c.hidden && c.getEditor()){
                        c.getEditor().focus();
                        break;
                    }
                }
            }
        },
    
    
        getTargetColumnIndex: function(pt){
            var grid = this.grid,
                v = grid.view,
                x = pt.left,
                cms = grid.colModel.config,
                i = 0,
                match = false;
            for(var len = cms.length, c; c = cms[i]; i++){
                if(!c.hidden){
                    if(Ext.fly(v.getHeaderCell(i)).getRegion().right >= x){
                        match = i;
                        break;
                    }
                }
            }
            return match;
        },
    
    
        startMonitoring : function(){
            if(!this.bound && this.monitorValid){
                this.bound = true;
                Ext.TaskMgr.start({
                    run : this.bindHandler,
                    interval : this.monitorPoll || 200,
                    scope: this
                });
            }
        },
    
    
        stopMonitoring : function(){
            this.bound = false;
            if(this.tooltip){
                this.tooltip.hide();
            }
        },
    
    
        isValid: function(){
            var valid = true;
            this.items.each(function(f){
                if(!f.isValid(true)){
                    valid = false;
                    return false;
                }
            });
            return valid;
        },
    
    
        // private
        bindHandler : function(){
            if(!this.bound){
                return false; // stops binding
            }
            var valid = this.isValid();
            if(!valid && this.errorSummary){
                this.showTooltip(this.getErrorText().join(''));
            }
            this.btns.saveBtn.setDisabled(!valid);
            this.fireEvent('validation', this, valid);
        },
    
    
        lastVisibleColumn : function() {
            var i = this.items.getCount() - 1,
                c;
            for(; i >= 0; i--) {
                c = this.items.items[i];
                if (!c.hidden) {
                    return c;
                }
            }
        },
    
    
        showTooltip: function(msg){
            var t = this.tooltip;
            if(!t){
                t = this.tooltip = new Ext.ToolTip({
                    maxWidth: 600,
                    cls: 'errorTip',
                    width: 300,
                    title: this.errorText,
                    autoHide: false,
                    anchor: 'left',
                    anchorToTarget: true,
                    mouseOffset: [40,0]
                });
            }
            var v = this.grid.getView(),
                top = parseInt(this.el.dom.style.top, 10),
                scroll = v.scroller.dom.scrollTop,
                h = this.el.getHeight();
    
    
            if(top + h >= scroll){
                t.initTarget(this.lastVisibleColumn().getEl());
                if(!t.rendered){
                    t.show();
                    t.hide();
                }
                t.body.update(msg);
                t.doAutoWidth(20);
                t.show();
            }else if(t.rendered){
                t.hide();
            }
        },
    
    
        getErrorText: function(){
            var data = ['<ul>'];
            this.items.each(function(f){
                if(!f.isValid(true)){
                    data.push('<li>', f.getActiveError(), '</li>');
                }
            });
            data.push('</ul>');
            return data;
        }
    });
    Ext.preg('roweditor', Ext.ux.grid.RowEditor);

Similar Threads

  1. Replies: 1
    Last Post: 15 Sep 2009, 6:47 PM
  2. Replies: 1
    Last Post: 26 Aug 2009, 11:41 PM
  3. [FIXED][3.0rc1] row editor doesn't work in IE Quirks mode
    By wopenonline111 in forum Ext 3.x: Bugs
    Replies: 8
    Last Post: 4 Jun 2009, 4:31 AM
  4. [FIXED] [3.0rc1] row editor doesn't work in IE Quirks mode
    By wopenonline111 in forum Ext 2.x: Bugs
    Replies: 2
    Last Post: 15 Apr 2009, 1:34 PM

Thread Participants: 6