Results 1 to 7 of 7

Thread: [OPEN-1242] Store's remoteSort requests ignore a field's mapping value

    Thank you for reporting this bug. We will make it our priority to review this report.
  1. #1
    Ext User
    Join Date
    Aug 2010
    Location
    Paris
    Posts
    3

    Default [OPEN-1242] Store's remoteSort requests ignore a field's mapping value

    Ext version tested:
    • Ext 3.3.0


    Adapter used:
    • ext


    css used:
    • only default ext-all.css




    Browser versions tested against:
    • FF3 (firebug 1.3.0.10 installed)
    • Safari 4


    Operating System:
    • Mac OS X 10.6


    Description:
    I'm not sure this count as a bug but the behaviour of Ext.data.Store's remoteSort seems inconsistant with other's client to server data operations as it will request that sorting be done using a field's name instead of the field's mapping when a mapping exists.

    The point of mapping field's name should be to allow different semantics on the server than on the client. It works as expected when using an Ext.data.Writer to save a store on the server. The field's name are converted back to the mapping value.

    Test Case:

    Given this store :
    Code:
    TestStore = Ext.extend(Ext.data.JsonStore, {
        constructor: function(cfg) {
            cfg = cfg || {};
            TestStore.superclass.constructor.call(this, Ext.apply({
                storeId: 'TestStore1',
                root: 'data',
                writer: new Ext.data.JsonWriter({
                  encode:false,
                  writeAllFields:true
                }),
                autoSave:false,
                remoteSort:true,
                proxy: new Ext.data.HttpProxy({
                  method:"POST",
                  api: {
                      read: {url: '/read.json', method: 'GET'},
                      create: "/create.fake",
                      update: "/update.fake",
                      destroy: "/destroy.fake" 
                  }
                }),
                fields: [
                    {
                        name: 'id',
                        allowBlank: false,
                        type: 'int'
                    },
                    {
                        name: 'arg1'
                    },
                    {
                        name: 'arg2',
                        mapping: 'real_name_arg2'
                    }
                ]
            }, cfg));
        }
    });
    TestStore = new TestStore();
    load.json :
    Code:
    {"message":"","data":[
    {"id":1, "arg1":"record1_arg1", "real_name_arg2":"record1_arg2"}
    ],"success":true,"total":1}

    Steps to reproduce the problem:
    • Request to sort by "arg2"
    • TestStore.sort('arg2', 'ASC');


    The result that was expected:


    The result that occurs instead:


    Screenshot or Video:


    Debugging already done:
    • A store always use a field's name for all sorting operation (including remoteSort)


    Possible fix:
    • Modify store's sort function to use a field's mapping is one is available
      Well since this behaviour has been in Ext forever, it could potentially break existing applications to change it now but adding a remoteSortUseMapping(bool) options to the store config would solve this.
    Last edited by le_lag; 27 Aug 2010 at 2:37 AM. Reason: grammar

  2. #2
    Ext JS Premium Member sumit.madan's Avatar
    Join Date
    May 2009
    Location
    Bangalore, India
    Posts
    126

    Default

    I confirm that this is also the case in ExtJS version 3.2.2, a mapping should always translate the posted field dataIndex, if present.

    In addition to sort, the groupBy parameter also ignores a mapped dataIndex.

  3. #3
    Sencha User Condor's Avatar
    Join Date
    Mar 2007
    Location
    The Netherlands
    Posts
    24,246

    Default

    'mapping' is only in a single direction from server data to client data. It isn't used to do the reverse (and it can't be used - 'mapping' can even be a function!).

    I you want, you can modify the parameters that are actually sent to the server in the beforeload event of the store.

  4. #4
    Ext JS Premium Member sumit.madan's Avatar
    Join Date
    May 2009
    Location
    Bangalore, India
    Posts
    126

    Default

    Quote Originally Posted by Condor View Post
    'mapping' is only in a single direction from server data to client data. It isn't used to do the reverse (and it can't be used - 'mapping' can even be a function!).
    A writable store maps the dataIndexes when posting new records or edited records to server. If mapping is unidirectional only, then this behavior should not exist.

  5. #5
    Ext User
    Join Date
    Aug 2010
    Location
    Paris
    Posts
    3

    Default

    I agree with sumit.madan.

    If you use the DataProxy API with a store, the mapping is used to write back to the backend.

    It seems only logical this works this way : if your backend identify a field with a name, you need to send back the same name if you want it to understand your request.

    Since the server/client mapping is known in the fields configuration, I can't see how to justify sending a client specific info to the server hoping it will understand it...

    Example Firebug Console Log :
    Code:
    >>> TestStore.load();
      GET http://localhost:3000/read.json?_dc=1282900743785
    >>> TestStore.getAt(0).set('arg2', 'new arg2');
    >>> TestStore.save();
      POST http://localhost:3000/update.fake
    
      POST data
        arg1        "record1_arg1"
        id            1
        real_name_arg2   "new arg2"    # <- the server is returned the proper
                                                          # mapping name for the field
    
        Source
        {"data":{"id":1,"arg1":"record1_arg1","real_name_arg2":"new arg2"}}
    Using the beforeload event is a smart workaround but I feel the framework would behave in a more consistent manner if it could directly use the mappings.

  6. #6
    Ext User
    Join Date
    Aug 2010
    Location
    Paris
    Posts
    3

    Default

    Here's a patch that solves the issue for store's remotesort while not breaking anyone's existing applications.

    Code:
    *** OriginalStore.js	2010-07-27 14:38:48.000000000 +0200
    --- Store.js	2010-08-27 15:46:02.000000000 +0200
    ***************
    *** 166,185 ****
    --- 166,192 ----
           * {@link Ext.grid.Column#header header} causes the current page to be requested from the server appending
           * the following two parameters to the <b><tt>{@link #load params}</tt></b>:<div class="mdetail-params"><ul>
           * <li><b><tt>sort</tt></b> : String<p class="sub-desc">The <tt>name</tt> (as specified in the Record's
           * {@link Ext.data.Field Field definition}) of the field to sort on.</p></li>
           * <li><b><tt>dir</tt></b> : String<p class="sub-desc">The direction of the sort, 'ASC' or 'DESC' (case-sensitive).</p></li>
           * </ul></div></p>
           */
          remoteSort : false,
      
          /**
    +      * @cfg {boolean} remoteSortUseMapping <tt>true</tt> if a store field's mapping must be used when sorting using remoteSort = true
    +      * If no mapping exists, the field name is used.
    +      * Defaults to <tt>false</tt>).
    +      */
    +     remoteSortUseMapping : false,
    + 
    +     /**
           * @cfg {Boolean} autoDestroy <tt>true</tt> to destroy the store when the component the store is bound
           * to is destroyed (defaults to <tt>false</tt>).
           * <p><b>Note</b>: this should be set to true when using stores that are bound to only 1 component.</p>
           */
          autoDestroy : false,
      
          /**
           * @cfg {Boolean} pruneModifiedRecords <tt>true</tt> to clear all modified record information each time
           * the store is loaded or when a record is removed (defaults to <tt>false</tt>). See {@link #getModifiedRecords}
           * for the accessor method to retrieve the modified records.
    ***************
    *** 833,853 ****
           * </ul>
           * @return {Boolean} If the <i>developer</i> provided <tt>{@link #beforeload}</tt> event handler returns
           * <tt>false</tt>, the load call will abort and will return <tt>false</tt>; otherwise will return <tt>true</tt>.
           */
          load : function(options) {
              options = Ext.apply({}, options);
              this.storeOptions(options);
              if(this.sortInfo && this.remoteSort){
                  var pn = this.paramNames;
                  options.params = Ext.apply({}, options.params);
    !             options.params[pn.sort] = this.sortInfo.field;
                  options.params[pn.dir] = this.sortInfo.direction;
              }
              try {
                  return this.execute('read', null, options); // <-- null represents rs.  No rs for load actions.
              } catch(e) {
                  this.handleException(e);
                  return false;
              }
          },
      
    --- 840,865 ----
           * </ul>
           * @return {Boolean} If the <i>developer</i> provided <tt>{@link #beforeload}</tt> event handler returns
           * <tt>false</tt>, the load call will abort and will return <tt>false</tt>; otherwise will return <tt>true</tt>.
           */
          load : function(options) {
              options = Ext.apply({}, options);
              this.storeOptions(options);
              if(this.sortInfo && this.remoteSort){
                  var pn = this.paramNames;
                  options.params = Ext.apply({}, options.params);
    !             var f = this.fields.get(this.sortInfo.field);
    !             if(this.remoteSortUseMapping && f && f.mapping) {
    !                 options.params[pn.sort] = f.mapping;
    !             } else {
    !               options.params[pn.sort] = this.sortInfo.field;
    !             }
                  options.params[pn.dir] = this.sortInfo.direction;
              }
              try {
                  return this.execute('read', null, options); // <-- null represents rs.  No rs for load actions.
              } catch(e) {
                  this.handleException(e);
                  return false;
              }
          },

  7. #7
    Ext JS Premium Member sumit.madan's Avatar
    Join Date
    May 2009
    Location
    Bangalore, India
    Posts
    126

    Default

    @le_lag
    Thanks!

    A small observation, Store.fields MixedCollection may not exist on load, if it is configured by metaData from server.

    Here are the overrides for sending the sort and the groupBy params based on the mapping. Only apply the override if you want the sort and groupBy params to contains mapped fields dataIndexes.

    Code:
    Ext.override(Ext.data.Store, {
        load : function(options) {
            options = Ext.apply({}, options);
            this.storeOptions(options);
            if (this.sortInfo && this.remoteSort) {
                var pn = this.paramNames;
                options.params = Ext.apply({}, options.params);
    
                var field = (this.fields instanceof Ext.util.MixedCollection) ? this.fields.get(this.sortInfo.field): null;
                var sortInfoField = (field && field.mapping) ? field.mapping : this.sortInfo.field;
    
                options.params[pn.sort] = sortInfoField;
                options.params[pn.dir] = this.sortInfo.direction;
            }
            try {
                return this.execute('read', null, options); // <-- null represents rs.  No rs for load actions.
            } catch(e) {
                this.handleException(e);
                return false;
            }
        }
    });
    
    Ext.override(Ext.data.GroupingStore, {
        applyGroupField: function(){
            if (this.remoteGroup) {
                if(!this.baseParams){
                    this.baseParams = {};
                }
    
                var field = (this.fields instanceof Ext.util.MixedCollection) ? this.fields.get(this.groupField): null;
                var groupField = (field && field.mapping) ? field.mapping : this.groupField; 
    
                Ext.apply(this.baseParams, {
                    groupBy : groupField,
                    groupDir: this.groupDir
                });
    
                var lo = this.lastOptions;
                if (lo && lo.params) {
                    lo.params.groupDir = this.groupDir;
    
                    //this is deleted because of a bug reported at http://www.extjs.com/forum/showthread.php?t=82907
                    delete lo.params.groupBy;
                }
            }
        }
    });

Similar Threads

  1. Replies: 6
    Last Post: 20 May 2010, 7:16 PM
  2. Mapping form field to difference store variable name
    By acetinick in forum Ext 2.x: Help & Discussion
    Replies: 1
    Last Post: 2 Oct 2008, 7:26 AM
  3. group field ignore custom renderered value
    By davidchantf in forum Ext 2.x: Help & Discussion
    Replies: 0
    Last Post: 29 Nov 2007, 10:12 AM
  4. a2: Datastore: remotesort fails if name is not equal mapping
    By Wolfgang in forum Ext 2.x: Help & Discussion
    Replies: 3
    Last Post: 12 Mar 2007, 12:45 PM
  5. Field mapping a Select and boolean data mapping
    By lucas in forum Ext 2.x: Help & Discussion
    Replies: 1
    Last Post: 8 Mar 2007, 5:35 AM

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •