Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Make proxy use extended Ext.data.Operation

I have extended Ext.data.Operation to implement a custom commitRecords method.

The Ext.data.Operation class is used for all communication between stores and their proxy.

The commitRecords method specifically is used to update the data in a data store according to data returned from a proxy writer.

I can't seem to get a grip on how to set up my proxies to use my extended version of Ext.data.Operation.

I've been rifling through the Ext.data.* package but can't seem to find where the Ext.data.Operation is created so I will know what class to tell to use this new extended Ext.data.Operation class with the custom commitRecords method.

Has anyone else extended this before, could give me some pointers?

like image 814
egerardus Avatar asked Oct 07 '22 21:10

egerardus


1 Answers

I found it, the batch method of Ext.data.Proxy is where an Ext.data.Operation object is created to send to the server.

I extended Ext.data.proxy.Ajax with a new batch method where I just switch out the new Ext.data.Operation for my own Operation class.

EDIT

Only because you asked DmitryB. The short story about why I had to implement my own commitRecords method is that I needed my data models "internalId" fields to match the actual database record ID field. I won't go into why exactly, it's too convoluted for me to express, but here's what I did:

How I understand it, the commitRecords method is fired as one of the last actions when calling store.sync() it automatically replaces the dirty records on the client side with the new server side records as long as you write your server side controller to return the new server record in the Ajax response, it does this whenever the sync request does an insert or update.

The official implementation of commitRecords tries to match this returned server record to the dirty client record by using the "internalId" field of the data model.

Obviously, I have no idea what the next incremental database ID is going to be for new records, so I cannot assign it on the client side as the ID before the record syncs with the database, therefore the server record will never match be able to match up against the dirty client record's internalId when commitRecords is called, i.e. the client record will not get the correct database ID, which I need.

So, because all of my writable data models for this app have a "create_time" field I decided to make the commitRecords method match the server records with the client records using the "create_time" field instead of "internalId".

Here is the extended Ext.data.Operation class, where I did this:

Ext.define('MyApp.ux.QueryOperation', {
    extend: 'Ext.data.Operation',

    /** 
     * Use the date_created timestamp if we cant match to an ID.
     * This allows client records that did not previously exist on the server
     * to be updated with the correct server ID and data
     * NB: All implementing data models require a "date_created" field.
     */
    commitRecords: function (serverRecords) {
        var me = this,
            mc, index, clientRecords, serverRec, clientRec;
        if (!me.actionSkipSyncRe.test(me.action)) {
            clientRecords = me.records;
            if (clientRecords && clientRecords.length) {
                if (clientRecords.length > 1) {
                    mc = new Ext.util.MixedCollection();
                    mc.addAll(serverRecords);
                    Ext.each(clientRecords, function(clientRec) {
                        serverRec = mc.findBy(function(record) {
                            var clientId = clientRec.getId(),
                                clientTime = clientRec.get('date_created').getTime(),
                                serverTime = record.get('date_created').getTime();
                                if(clientId && record.getId() === clientId) {
                                    return true;
                                }
                                // timestamp can be within 2ms of record
                                // (it seems to change slightly in serialization)
                                return (clientTime > serverTime - 2 && clientTime < serverTime + 2);
                        });
                        me.updateClientRecord(clientRec, serverRec);
                    });
                } else {
                    clientRec = clientRecords[0];
                    serverRec = serverRecords[0];
                    me.updateClientRecord(clientRec, serverRec);
                }
                if (me.actionCommitRecordsRe.test(me.action)) {
                    for (index = clientRecords.length; index--; ) {
                        clientRecords[index].commit();
                    }
                }
            }
        }
    },

});

As I mentioned in the answer, I found that I had to extend proxy to make use of my new Operation class. The only thing I extended was the batch method, replacing only two lines in the method which said new Ext.data.Operation to now say new MyApp.ux.QueryOperation (my new Operation class above). This then called my own commitRecords method when a response came back from the server. I also gave the extended proxy an alias "proxy.query" so that I could tell my stores to use it like this:

Ext.define('MyApp.store.MyStore', {
    extend: 'Ext.data.Store',
    requires: [
        'ST.ux.QueryProxy',
    ],
    title: 'Student',
    model: 'MyApp.model.MyModel',
    proxy: {
        type: 'query',
        // ... ^^^^^ uses my QueryProxy now
        // other configs...
    }
});

(If it seems like I am going about this wrong way or missed something in the docs, please let me know. I would be happier with a built in method of achieving this functionality.)

like image 92
egerardus Avatar answered Oct 12 '22 03:10

egerardus