Skip to content

January 6, 2011

24

Minor Interaction Improvements on Ext JS Row Editor Example

by Joe Kuan

I’ve been exploring the Ext-JS Row Editor Example which the whole presentation and user experience are very slick. However, I do find couple minor problems with the example.

Issue 1. When click on the ‘Add Employee’ button, it automatically inserts a new row at the top. However, if you click on another row, the Row Editor will move on to the selected row. In my view, this shouldn’t be allowed unless the user clicks the Update or Cancel buttons because the state of the new row is still in modified state.

Workaround:
Interestingly when click on an existing row, modify it and then try to click on another row, the UI will prompt an error text. This should also apply in this scenario.

After studying the RowEditor source code, there is a workaround to apply it ‘Add Employee’.

        tbar: [{
            iconCls: 'icon-user-add',
            text: 'Add Employee',
            handler: function(){
                var e = new Employee({
                    name: 'New Guy',
                    email: 'new@exttest.com',
                    start: (new Date()).clearTime(),
                    salary: 50000,
                    active: true
                });
                editor.stopEditing();
                store.insert(0, e);
                grid.getView().refresh();
                grid.getSelectionModel().selectRow(0);
                editor.startEditing(0);
                editor.values = {};
            }

When RowEditor.startEditing() is called, it first copies all the values from the selected row. When the modification is detected without updating, the row is marked as dirty and hence the error message. The above added line is to remove all the copied values of the new inserted row which forces it to mark as dirty.

Issue 2: Relate to the first issue. Click on the ‘Add Employee’ button to insert a new row and a Row Editor is prompted to the user. If the Cancel button is clicked, the new row doesn’t disappear which should be because the it is not saved.

Workaround:
One quick way (hacky way) is to modify ‘Add Employee’ handler function that inserts a new field inside the editor object for flagging the new row data. Then checks for the flag in ‘canceledit’ event handler and removes the row if necessary and resets the flag.
Alternatively (my prefer way), you can return extra field, new_user, from the JsonStore with the value false for all the rows. In the ‘Add Employee’ button handler, creates a new Record object with new_user field as true. Then in ‘canceledit’ event handler, you can do something like this:

editor.on('canceledit',
   function(roweditor, forced) {
     editor.stopEditing();
     var s = grid.getSelectionModel().getSelections();
     for (var i = 0; i < s.length; i++) {
       r = s[i];
       if (r.data.new_user)
         grid.getStore().remove(r);
     }
   }
);

This way you don’t need to mess inside the Ext JS objects.

Advertisements
24 Comments Post a comment
  1. Deco
    Jan 31 2011

    Greate post. Just what I needed. Do you have a workarounde if a user adds muliple rows of the same value? Example: Click on the ‘Add Employee’ button to insert a new row. Click again on the ‘Add Employee’ button. It should check the record if the ‘Name’ value already exists. Would be greate if you have a workaround for this. The same thing for ‘Update’ button.

    Reply
    • Joe Kuan
      Feb 1 2011

      No, I haven’t explored the multiple rows but I’ll see what I can do.

      Thanks
      Joe

      Reply
    • Joe Kuan
      Feb 2 2011

      I think the best workaround is when the user clicks the add button, the handler disables the add button. Then the update and cancel handler always enable the add button.

      Reply
  2. Mar 28 2011

    Great information. Playing around with your code I found something. Maybe I’m wrong, but with the workaround of the cancelEdit, if a user tries to modify a row and then change his mind and press cancel, won’t it delete it too?

    I changed the original RowEditor store with one of my own and that’s what it happens when I click Cancel in an unchanged row. Now, it could be when changing the variables I messed up something, but my structure follows the same as the example.

    As a workaround I used a global variable that changes when called through the “Add” handler and then inside your “if (r.data.new_user)” I add “&& variable”. The result was something like this:

    if (r.data.username && addedNew) //username is my own new variable

    I tried to user the “modified” and “store.data.length” variables without success. Could you come up with a more elegant solution? (If there’s a problem to begin with)

    Best regards,
    -JJ

    Reply
  3. Joe Kuan
    Mar 28 2011

    Remember, when the Store gets all the records from the server side, I have programmed the server side to return all the records with a extra field new_user == false.
    If the user tries to modify a row that is already existed (ie. The record is retrieved from the database) and hits cancel, the row doesn’t get removed. Because record.data.new_user is false.
    So when I click create new user, the event handler inserts a new record into the Grid’s Store with new_user == true. Then if the user clicks cancel, the entire row will get removed.

    What you have described, I think it is similar to the first approach to flag the Add New button. Instead of putting the flag inside the RowEditor object, you declare as global variable.

    Hope this answer your question

    Reply
    • Mar 28 2011

      There you go. Since I changed the whole store, I forgot the purpose of the new_user variable. Thank you!

      Reply
  4. IcebergDelphi
    Apr 15 2011

    Hi, I need to Know about: afteredit: function(roweditor, changes, record, rowIndex)

    or i need to know when the editor is editing, is there a way to know when the raw editor is editing?

    Thank Ya.

    Reply
    • Joe Kuan
      Apr 15 2011

      afteredit is for when the user click Save after modifying the row and passed the validation.

      If you want to know WHILE the editor is being edited, then in your columns of the GridPanel do something like this (I think but not 100% sure):


      columns: [{
      header: 'Name',
      dataIndex: 'name',
      editor: {
      xtype: 'textfield',
      enableKeyEvents: true,
      listeners: {
      keypress: function(textfield, event) {

      }
      }
      }]

      Do you want to know what the users have typed or just for some input validation purposes? If later, then it is much easier to achieve with VType.

      Hope this helps

      Reply
      • IcebergDelphi
        Apr 15 2011

        Ok i’ve got the solution i write some kind of Flag:
        var editor = new Ext.ux.grid.RowEditor({
        saveText: ‘Guardar’,
        cancelText:’Cancelar’,
        clicksToEdit: 2,
        listeners: {
        afteredit: function(roweditor, changes, record, rowIndex) {
        if (Status==0) <<<<<<FLAG If 0 Editing Else Insert
        {
        alert('Editando');
        }
        else
        {
        Ext.Ajax.request({…….Insert

  5. IcebergDelphi
    Apr 15 2011

    Tanx Joe Kuan , I need To Know when the data is Modified or if the data is edited then fire a updateEvent else just insert, here is my code:
    var editor = new Ext.ux.grid.RowEditor({
    saveText: ‘Guardar’,
    cancelText:’Cancelar’,
    clicksToEdit: 2,
    listeners: {
    afteredit: function(roweditor, changes, record, rowIndex) {
    if (roweditor.startEditing==true)
    {
    alert(‘Editando’);
    }
    else
    {
    Ext.Ajax.request({
    url:’/CursosExjs/crudroweditor/php/IEDCd.php?Opcion=Agregar’,
    method:’POST’,
    params:
    {
    Titulo:record.get(‘Titulo’),
    Interprete:record.get(‘Interprete’),
    Anio:record.get(‘Anio’),
    },
    });
    }
    },
    canceledit:function(rowEditor){
    var record = MyGrd.store.getAt(editor.rowIndex);
    if(record==null) {
    MyGrd.store.removeAt(editor.rowIndex);
    MyGrd.getView().refresh();
    }
    return true;
    }

    },
    });

    Reply
  6. IcebergDelphi
    Apr 15 2011

    Tanks Joe Kuan i need to Know the next: If MyRecord was Edited then Fire Event: Update else FireEvent Insert, the 2 events are sended via AjaxRequest to PHP and Mysql.

    Reply
    • Joe Kuan
      Apr 15 2011

      In my opinion, CRUD operation and Restful URL is what you need. ExtJS provides samples for them. It is a bit of a learning curve but it is worth in at the end. Once you know it, it is very easy and little code to do insert, update, view, and delete.

      But if you don’t want to use CRUD, then …

      Basically, a new record is inserted to the store when you click add button. Then this record will have an empty id value. If the user clicks to modify an existing row, the id field has a valid value. For the save operation, then you just the get the new/changed record from the store and submit to the server side. With the value of the id, your server side should know the difference of insert or modify operation.

      I strongly recommend you to study the source code of the RowEditor example, JsonReader, JsonWriter and HttpProxy.

      Reply
  7. IcebergDelphi
    Apr 15 2011

    Hi again i resolved I just Write a Flag : If Status==0 Then Editing…AjaxRequest to PHP and Mysql else Insert……..

    Thanks

    Reply
  8. Farish
    Jul 8 2011

    Hi,

    I am using Ext JS 4. I am creating a row editing plugin as shown below:

    var rowEditing = Ext.create(‘Ext.grid.plugin.RowEditing’, {
    id:’rowEditing’,
    clicksToEdit: 2
    });

    but this plugin doesnt have a cancel/canceledit event… it only has edit, beforeedit and validateedit events. How can I delete the newly added row if a user presses cancel?

    Regards,
    Farish

    Reply
    • Jul 8 2011

      Greetings Farish, I haven’t tried Extjs4 yet, but in the documentation the RowEditing plug in has a config option called “autocancel”:

      autoCancel : Boolean
      true to automatically cancel any pending changes when the row editor begins editing a new row. false to force the user to explicitly cancel the pending changes. Defaults to true

      You should check it out to see if that fits your needs.
      http://www.nanpowan.com/lib/ext-4.0.0/docs/api/Ext.grid.plugin.RowEditing.html

      Reply
      • Farish
        Jul 8 2011

        Thanks for your quick reply. autoCancel doesn’t do what I want… I am now looking at the cancelEdit method which is called when the cancel button is pressed but so far, I have observed that its also called when the grid is loaded and on some other events… will post my solution if i find something.

      • Farish
        Jul 8 2011

        Finally got a working solution for Ext JS 4. Here it is:

        // Override the cancelEdit function of RowEditing plugin
        Ext.override(Ext.grid.plugin.RowEditing, {
        cancelEdit: function() {
        var me = this;

        if (me.editing) {
        me.getEditor().cancelEdit();
        me.callParent(arguments);

        this.fireEvent(’canceledit’, this.context);
        }
        }
        });

        // Create plugin to be used in grid:
        var rowEditing = Ext.create(’Ext.grid.plugin.RowEditing’, {
        id:’rowEditing’,
        clicksToEdit: 2
        });

        // Use canceledit event to remove the added record from the store (or use what you want in this function!)
        rowEditing.on(’canceledit’, function(context) {
        context.record.store.remove(context.record);
        });

        Hope this helps others.

        Regards,
        Farish

  9. michael@haston.name
    Aug 24 2011

    Exactly what I was looking for. All of your tips in the blog have been implemented and working just like I hoped. I do have a question or two …

    1. Do you have an example of using vType with the RowEditor?

    2. I have a window with a grid in it. The grid gets loaded on “activate”. When I add a new row and then delete it, the grid refreshes and still has the row that I removed. I just looked at it appears that the “activate” gets fired off before the submit to remove the record does from my remove button. Very unexpected!

    Reply
    • Joe Kuan
      Aug 24 2011

      1) No, I haven’t but as far as I know, you just use the vtype as with Ext.form.Textfield, like in the original example.

      2) The grid is binded with a Store object and it is important how you setup the Store to pass the new, modify, delete record to the server side.
      You can use CRUD (which I prefer) or manually invoke Ext.Ajax.request.

      Also make sure you check the HTTP message using your browser debugger to inspect the request parameters and the content in the response message.

      Reply
  10. Mike
    Aug 25 2011

    I probably don’t understand what’s going on as well as I should. Here is my code:

    {
    					xtype : 'button',
    					text : 'Remove User',
    					iconCls : 'icon-user_delete',
    					ref : '../removeBtn',
    					disabled : true,
    					handler : function() {
    
    						Ext.MessageBox.confirm(' ',
    								'Are you sure you want to do that?', function(
    										btn) {
    									// console.log(btn);
    									if (btn == 'yes') {
    
    										editor.stopEditing();
    										var s = userMaintenanceGrid
    												.getSelectionModel()
    												.getSelections();
    										for (var i = 0, r; r = s[i]; i++) {
    
    											Ext.Ajax.request({
    												url : '/cgidev2p/jsonsbm002.pgm',
    												method : 'POST',
    												params : {
    													dummy : 'remove-record',
    													pAction : 'remove',
    													pUserid : r.get('gUserid'),
    													pName : r.get('gName'),
    													pStates : r.get('gStates'),
    													pZips : r.get('gZips')
    												},
    												success : function() {
    													userMaintenanceStore.remove(r);
    
    												}
    											});
    											userMaintenanceStore.remove(r);
    										};
    									}
    								});
    
    					}
    				}
    

    When I confirm the pressing of the button the store to load my grid is called and then the Ajax.request is called. I guess Activate on the window with the grid fires before the submit? It’s really screwing things up for me.

    Reply
    • Joe Kuan
      Aug 25 2011

      First, I would suggest you to make sure the server have received the HTTP request properly and deleted the user. If so, then what response message do you send back from /cgidev2p/jsonsbm002.pgm? JSON, XML, or just normal string.

      You can check the return from success handler, here is a mock up example

      success(response) {
        // Debug the response from the url action
        console.log(response.responseText);
      
        // Decode JSON if necessary and check the result
        var result = Ext.decode(response.responseText)
      
        // Reload the Store from the server if the result of the update is good
        // The reload will also trigger the Grid to update with the new data
        if (result.success == true) 
          userMaintenanceStore.reload();
        else
          Ext.Msg.alert('Error', result.errormsg);
      }
      

      Store class is the backbone of data access between the client and server side. If you setup the Store class properly, your application becomes easy to extend. All the events between your widget components will trigger each other nicely. I suggest you study and practice the Store class a lot.

      Also read about how to use BasicForm.updateRecord and BasicForm.loadRecord. They are very handy.

      Reply
  11. unknown
    Oct 31 2011

    In my GWT application there are 3 tabs.Each tabs has certain rows.I have used Gwt RowEditor function to edit this row.I want to display an error message when i navigate away from a particular tab without saving or discarding the changes .

    Reply
  12. Oct 2 2014

    Wonderful web site. A lot of helpful info here.
    I am sending it to a few pals ans additionally
    sharing in delicious. And naturally, thank you
    on your effort!

    Reply
  13. Dec 11 2014

    Navigate to new ExtJS 5.0 sample:
    http://dev.sencha.com/ext/5.0.0/examples/grid/row-editing.html
    sort grid, add new Employee.
    Do You have workaround for this bug ?

    Reply

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Note: HTML is allowed. Your email address will never be published.

Subscribe to comments

%d bloggers like this: