Page 3 of 4 FirstFirst 1234 LastLast
Results 21 to 30 of 37

Thread: Whats the replacement for Store.getModifiedRecords()?

  1. #21
    Sencha User
    Join Date
    Dec 2008
    Location
    Munich (Bavaria/Germany)
    Posts
    291

    Default

    I updated the example, the changed records are marked as dirty but getUpdatedRecords still delivers 0:

    Code:
    <%@ page language="java" contentType="text/html; charset=ISO-8859-1"
        pageEncoding="ISO-8859-1"%>
    
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
        <title>Insert title here</title>
        
         <link id="extjs-theme-base" rel="stylesheet" type="text/css" href="js/ext-4.0.2a/resources/css/ext-all.css">
        <script type="text/javascript" src="js/ext-4.0.2a/bootstrap.js"></script>
    
        <script type="text/javascript">
        
            Ext.onReady(function(){
                
                 Ext.data.AbstractStore.override({
                       getRecords : function(){
                           
                         var me = this;
                         return me.getNewRecords().concat(
                             me.getUpdatedRecords()).concat(
                             me.getRemovedRecords());
                      }
                });
            
                
                Ext.define ('standardCF', {
                    extend: 'Ext.data.Model',
                    fields: [
                        'rowKey',
                        'columnCount'            
                    ]
                });
                
                
                this.store = Ext.create ('Ext.data.Store', {
                    
                    model: 'standardCF',
                    data: [{rowKey:"123",columnCount:"1"},{rowKey:"456",columnCount:"2"}],
                    autoLoad: true
                });            
                
                
                var grid = Ext.create ('Ext.grid.Panel', {
    
                    store: this.store,
                    autoScroll: true,
                    frame: true,
                    columns: [
                         {header: "Row Key", flex: 1, dataIndex: 'rowKey', sortable: true, field: Ext.create ('Ext.form.TextField', {
                             allowBlank: false
                         })},
                        {header: "Val2", width: 100, dataIndex: 'columnCount', sortable: true}
                    ],
                    stripeRows: true,
                    autoExpandColumn: 'rowKey',
                    selType: 'cellmodel',
                    plugins: [
                              Ext.create ('Ext.grid.plugin.CellEditing', {
                                  clicksToEdit: 1
                              })
                    ],
                    listeners: {
                        
                        edit: {
                            
                            fn: function (editor, row, options) {
                                
                                //alert (row.record);
                            },
                            scope: this
                        }                    
                    }
                });
                
                
                new Ext.Window ({
                
                    renderTo: Ext.getBody(),
                    title: 'Hello, World!',
                    height: 500,
                    width: 300,
                    layout: 'fit',
                    items: [
                        grid
                    ],
                    tbar: Ext.create ('Ext.toolbar.Toolbar', {
                        items: [
                            {
                                xtype:'button',
                                text:'GET',
                                scope: this,
                                handler: function() {
                                
                                    alert ("Updated records: " + this.store.getUpdatedRecords().length);
                                    
                                    var records = this.store.getRecords();
                                    for (var i = 0; i < records.length; i++) {
    
                                        alert (i + ' is dirty: ' + records[i].dirty);
                                    }
                                }
                            }
                        ]
                    })
                }).show();
                
                
            });
    
        </script>
        
    </head>
    
    <body>
    </body>
    </html>
    Checkout Apollo, an ExtJS4-based Apache Cassandra client: http://www.codefreun.de/en/apollo-en

  2. #22
    Sencha User hendricd's Avatar
    Join Date
    Aug 2007
    Location
    Long Island, NY USA
    Posts
    5,966

    Default

    @defcon1--

    Your playpen sample is not really structured to handle 'modified' treatment because the Store and Model lack sufficient record identification (when your data is specified inline) to prevent your records from being marked as 'phantoms'.

    To solve that, you'll need to define a proxy/reader that identifies the idProperty of your Model. (Without knowing the 'id' of the Model, the store assumes it is a new (phantom) record.)

    To qualify as an 'updated' record, it must:
    a) NOT be phantom (new record)
    b) must be valid
    c) have a 'dirty' indicator

    As this revised example demonstrates:
    Note: The second column is now the editable one, as the first field (rowKey) is now the 'id' field in this example.

    Code:
     Ext.onReady(function(){                           
           Ext.data.AbstractStore.override({                    
                 getModifiedRecords : function(){      //Ext 3.3.x equiv for all mods                                        
                      var me = this;                     
                      return me.getNewRecords().concat(                          
                               me.getUpdatedRecords()).concat(                           
                               me.getRemovedRecords());                   
                  }             
            });
    
            //Another required patch
           Ext.ModelManager.create = function(config, name, id) {
                var con = (typeof name == 'function') ? name : this.types[name || config.name];
                return new con(config, id || config[con.prototype.idProperty]);
           };
    
           Ext.define ('standardCF', {
                    extend: 'Ext.data.Model',
                    fields: [
                        'rowKey',
                        'columnCount'            
                    ]
                });
                
               
                this.store = Ext.create ('Ext.data.Store', {
                    
                    model: 'standardCF',
                    data: {rows: [{rowKey:"123",columnCount:"1"},{rowKey:"456",columnCount:"2"}]},
                    proxy: {
                       type: 'memory',
                       reader: {
                            type: 'json',
                            root: 'rows',
                            idProperty : 'rowKey'
                        }
                     }
                });   
                          
                var grid = Ext.create ('Ext.grid.Panel', {
    
                    store: this.store,
                    autoScroll: true,
                    frame: true,
                    columns: [
                         {header: "Row Key", flex: 1, dataIndex: 'rowKey', sortable: true},
                        {header: "Val2", width: 100, dataIndex: 'columnCount', sortable: true, 
                               field: Ext.create ('Ext.form.TextField', {allowBlank: false})
                         }
                    ],
                    stripeRows: true,
                    autoExpandColumn: 'rowKey',
                    selType: 'cellmodel',
                    plugins: [
                              Ext.create ('Ext.grid.plugin.CellEditing', {
                                  clicksToEdit: 1
                              })
                    ],
                    listeners: {
                        
                        edit: {
                            
                            fn: function (editor, row, options) {
                                
                                //alert (row.record);
                            },
                            scope: this
                        }                    
                    }
                });
                
                
                new Ext.Window ({
                
                    renderTo: Ext.getBody(),
                    title: 'Hello, World!',
                    height: 500,
                    width: 300,
                    layout: 'fit',
                    items: [
                        grid
                    ],
                    tbar: Ext.create ('Ext.toolbar.Toolbar', {
                        items: [
                            {
                                xtype:'button',
                                text:'GET',
                                scope: this,
                                handler: function() {
                                
                                    alert ("Updated records: " + this.store.getUpdatedRecords().length);
                                    
                                    var records = this.store.getRange(), // Gather all for analysis
                                         rec;
                                    for (var i = 0; i < records.length; i++) {
                                        rec = records[i];
                                        console.info (i, rec.internalId, ' is dirty: ' , rec.dirty, 'phantom:', rec.phantom, 'valid:', rec.isValid());
                                    }
                                }
                            }
                        ]
                    })
                }).show();
    Start snooping..
    "be dom-ready..."
    Doug Hendricks

    Maintaining ux: ManagedIFrame, MIF2 (FAQ, Wiki), ux.Media/Flash, AudioEvents, ux.Chart[Fusion,OFC,amChart], ext-basex.js/$JIT, Documentation Site.


    Got Sencha licensing questions? Find out more here.


  3. #23
    Sencha User pmachner's Avatar
    Join Date
    Jun 2011
    Location
    Krakw, Poland
    Posts
    54

    Default

    I've got a related question... For some reason my rows are never dirty but are always phantom.
    Here's what I'm doing:

    Code:
    store.load(//...loading 2 rows...
    store.sync();
    
    //adding 3rd row
    var r = Ext.create('MyModel', { modelId='1', key: 'value'});
    store.add(r);
    
    console.log('new: ');
    console.log(store.getNewRecords());
    console.log('updated: ');
    console.log(store.getUpdatedRecords());
    
    var recs = store.getRange();
    for (var i = 0; i < recs.length; i++) {
    	var rec = recs[i];
    	console.info (i, rec.internalId, ' is dirty: ' , rec.dirty, ' phantom:', rec.phantom, ' valid:', rec.isValid());
    }
    The above returns the following:
    Code:
    new:
    [Object { phantom=true, internalId="ext-record-5", more...}, Object { phantom=true, internalId="ext-record-6", more...}, Object { phantom=true, internalId="ext-record-7", more...}]
    updated:
    []
    0 ext-record-5 is dirty: false phantom: true valid: true
    1 ext-record-6 is dirty: false phantom: true valid: true
    2 ext-record-7 is dirty: false phantom: true valid: true
    I've got idProperty specified for my proxy. Also, my proxy is a PagingMemory proxy.

    What am I doing wrong? I would expect getNewRecords() to return just a single row, since sync() was called before adding the third row.

    Thanks a lot in advance

  4. #24
    Sencha User hendricd's Avatar
    Join Date
    Aug 2007
    Location
    Long Island, NY USA
    Posts
    5,966

    Default

    @pmachner--

    The 'idProperty' belongs on the reader.

    Can you post your Store, proxy configs, and load sequence?
    "be dom-ready..."
    Doug Hendricks

    Maintaining ux: ManagedIFrame, MIF2 (FAQ, Wiki), ux.Media/Flash, AudioEvents, ux.Chart[Fusion,OFC,amChart], ext-basex.js/$JIT, Documentation Site.


    Got Sencha licensing questions? Find out more here.


  5. #25
    Sencha User pmachner's Avatar
    Join Date
    Jun 2011
    Location
    Krakw, Poland
    Posts
    54

    Default

    yeah, I had it specified for the reader, but I wrote that for the proxy - sorry, my bad...
    Anyway, here's the sequence:
    Code:
    Ext.define('MyModel', {
        extend: 'Ext.data.Model',
        fields: [{name: 'modelId'}, {name: 'key'}]
    });
    	
    var store = new Ext.data.SimpleStore({
    	model: 'MyModel',
    	pageSize: 50,
    	proxy: {
               type: 'pagingmemory',
               data: twoRowsOfData,
               reader: {
                   type: 'array',
                   idProperty: 'modelId'
               }
    	}
    });
    
    //...
    
    store.load({ params: { start: 0, limit: 50, sort: 'key', dir: 'ASC', newData: true }});
    
    //...and here comes the logic from the previous post...

  6. #26
    Sencha User hendricd's Avatar
    Join Date
    Aug 2007
    Location
    Long Island, NY USA
    Posts
    5,966

    Default

    @pmachner--

    Well, been digging a bit more on use-cases like this, and found a couple bugs that make working with Array-based models a nuisance.

    In your case (and several others I've seen), had you chosen a JSON-backed store this might have been more straight-forward to deal with.

    But since Array models are simple flat records, the use of an Array ordinal is required (since for the purpose of identity, field names aren't much value in the current implementation).

    Your choice to declare the Model in advance is a good one and recommended moving forward. But you'll need to specify the 'idProperty' (as an ordinal only) EITHER on the Model or on the proxy's reader.

    (I'm not a fan of declaring such a property on the Model that is so specific to an Array structure, so I'd prefer to see that on the reader definition) Your call.

    Code:
    Ext.define('MyModel', {     
        extend: 'Ext.data.Model',     
        fields: [{name: 'modelId'}, {name: 'key'}],
        idProperty : 0
     });
    
    var store = new Ext.data.SimpleStore({     // Ext 3 alias for ArrayStore
        model: 'MyModel',     
        pageSize: 50,     
        proxy: {            
             type: 'pagingmemory',            
             data: twoRowsOfData,            
             reader: {                
                   type: 'array',               
                    idProperty: 0    //Note: Takes precedence over Model declaration
             }     
         } 
    });
    But, in order for ordinals to be used (especially 0) we have to patch a couple problems:
    Code:
    Ext.ModelManager.create = function(config, name, id) {
            var con = (typeof name == 'function') ? name : this.types[name || config.name];
            return new con(config, id || config[con.prototype.idProperty]);
        };
    
    Ext.override( Ext.data.reader.Reader, {
        buildExtractors: function(force) {
            var me          = this,
                idProp      = me.getIdProperty(),
                totalProp   = me.totalProperty,
                successProp = me.successProperty,
                messageProp = me.messageProperty,
                accessor;
    
            if (force === true) {
                delete me.extractorFunctions;
            }
    
            if (me.extractorFunctions) {
                return;
            }
    
            //build the extractors for all the meta data
            if (totalProp) {
                me.getTotal = me.createAccessor(totalProp);
            }
    
            if (successProp) {
                me.getSuccess = me.createAccessor(successProp);
            }
    
            if (messageProp) {
                me.getMessage = me.createAccessor(messageProp);
            }
    
            if (!Ext.isEmpty(idProp)) {    //^^^ Permits ordinal (eg. 0) for Arrays
                accessor = me.createAccessor(idProp);
    
                me.getId = function(record) {
                    var id = accessor.call(me, record);
                    return (id === undefined || id === '') ? null : id;
                };
            } else {
                me.getId = function() {
                    return null;
                };
            }
            me.buildFieldExtractors();
        }
    });
    
    Ext.override(Ext.data.reader.Array, {
    
        useSimpleAccessors : true,   // ^^^ No complex accessor nesting needed here
        /**
         * @private
         * Most of the work is done for us by JsonReader, but we need to overwrite the field accessors to just
         * reference the correct position in the array.
         */
        buildExtractors: function() {
            this.callParent(arguments);
    
            var fields = this.model.prototype.fields.items,
                i = 0,
                length = fields.length,
                extractorFunctions = [],
                map;
    
            for (; i < length; i++) {
                map = fields[i].mapping;
                extractorFunctions.push(function(index) {
                    return function(data) {
                        return data[index];
                    };
                }(Ext.value(map, i)));    //^^^ Fix
            }
    
            this.extractorFunctions = extractorFunctions;
        }
    });
    That should resolve the 'phantom : true' issues when bulk-loading models, AND ensures every record gets a valid internalId if you plan on doing CRUD on the store.

    Note to others following this: At this time, data.Stores defined with inline field collections (which yield Explicit Models) do not support the 'idProperty'. If you're going to 'CRUD the store', declare the Model first and use that reference instead of the in-line fields:[] collection. If working with a simple 'read-only' store, either approach will be fine.

    I'll get a ticket going on these.
    "be dom-ready..."
    Doug Hendricks

    Maintaining ux: ManagedIFrame, MIF2 (FAQ, Wiki), ux.Media/Flash, AudioEvents, ux.Chart[Fusion,OFC,amChart], ext-basex.js/$JIT, Documentation Site.


    Got Sencha licensing questions? Find out more here.


  7. #27
    Sencha User pmachner's Avatar
    Join Date
    Jun 2011
    Location
    Krakw, Poland
    Posts
    54

    Default

    Doug, thanks a lot for this very detailed explanation And for opening the ticket...
    I'll start implementing a fix right away. I might eventually just switch to a json format to avoid overrides of ExtJS classes in my code.

    One more request: could you paste the ticket link on this thread so that I know when the issue is resolved and can remove the overrides (if I decide to put them) from my code? Thanks in advance

    Best regards,
    Piotr

  8. #28
    Sencha User pmachner's Avatar
    Join Date
    Jun 2011
    Location
    Krakw, Poland
    Posts
    54

    Default

    Just a few words of followup. Doug, I added the fix to my code and it works. The two old records are not phantom now but the new one is Thanks again

  9. #29
    Sencha User pmachner's Avatar
    Join Date
    Jun 2011
    Location
    Krakw, Poland
    Posts
    54

    Default

    Sorry for multi-posting... Doug, now I have a problem with the store.sync() method...
    I change one of my model records (by using the model.set method), this record gets marked as dirty. Then I save all the changed record to the database and just after saving it (knowing that the save operation completed successfully) I call the store.sync() method which, I assume, should set dirty='false' for every record. But for some reason it doesn't - after store.sync(), the row that was dirty is still dirty and gets returned again in subsequent store.getUpdatedRecords() calls.
    Is this expected or is it a bug?

    Best regards,
    Piotr

  10. #30
    Sencha User hendricd's Avatar
    Join Date
    Aug 2007
    Location
    Long Island, NY USA
    Posts
    5,966

    Default

    Quote Originally Posted by pmachner View Post
    Sorry for multi-posting... Doug, now I have a problem with the store.sync() method...
    I change one of my model records (by using the model.set method), this record gets marked as dirty. Then I save all the changed record to the database and just after saving it (knowing that the save operation completed successfully) I call the store.sync() method which, I assume, should set dirty='false' for every record. But for some reason it doesn't - after store.sync(), the row that was dirty is still dirty and gets returned again in subsequent store.getUpdatedRecords() calls.
    Is this expected or is it a bug?

    Best regards,
    Piotr
    @Piotr

    [paging]memory proxy has no formal implementation for create/update/destroy operations. They were designed for read-only use. You'll need to implement (likely a subclass) appropriate methods (firing the expected callback listeners so sync can do it's job) to meet your needs. YOU have to respond like a server would.
    "be dom-ready..."
    Doug Hendricks

    Maintaining ux: ManagedIFrame, MIF2 (FAQ, Wiki), ux.Media/Flash, AudioEvents, ux.Chart[Fusion,OFC,amChart], ext-basex.js/$JIT, Documentation Site.


    Got Sencha licensing questions? Find out more here.


Page 3 of 4 FirstFirst 1234 LastLast

Posting Permissions

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