Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Extjs4: How to share data between multiple stores or models?

Tags:

extjs

extjs4

I'm new to Ext and I'm struggling to figure out Models Stores and Proxies.

The server returns one large JSON object. For example.

{ 
    "responseHeader":{ 
        "status":0, 
        "QTime":12, 
        "params":{ 
            "facet":"true", 
            "facet.limit":"40" 
        }
    },
    "response":{
        "numFound":3806,
        "start":0,
        "docs":[ 
            { 
                //Lots of fields
                "id":"1234",
                ...
                //Some array properties
                "testfield":[ 
                    "",
                    ""
                ],
                ...
            }
        ]
    },
    "facet_counts":{
        "facet_queries":{
            "email":3806
        },
        "facet_fields":{
           "emailaddress":{ 
            },
            "subject":{
                "candles":136,
                "filter":130 
            },
            "fromemail":{ 
            },
           //...
        },
        "facet_dates":{ },
        "facet_ranges":{}
    },
    "highlighting":{
        "some doc id":{
            "emailtext":[ " Tel.: blah blah <em>blah</em>" ],
            "combined":[ "<em>Email</em> To: blah blah blah" ]
        }
    }
}

I don't want to load this data more than once, I want to grab data from this object, for example the docs object, and put it into a grid. Then pull out another part to put into a selectbox.

How do I load this data once, yet create models and stores to give to grids and selectboxes, from it?

From what I read the proxy holds the servers response? So I tried creating a proxy out side of a store. Thinking I could use the same proxy with more than one store.

var myProxy1 = Ext.create('Ext.data.proxy.Proxy', {
    type: 'ajax',
    url : '../test',
    reader: {
        type: 'json',
        root: 'responseHeader'
    }
});

But when I pass myProxy1 to a store

Ext.define('Test', {
    extend: 'Ext.data.Model',
    fields: [
        {name: 'status', type: 'int'},
        {name: 'QTime',  type: 'int'},
        {name: 'param',  type: 'auto'}
    ]
});

var myStore = Ext.create('Ext.data.Store', {
    model: 'Test',
    proxy: myProxy1,
    autoLoad: true,
    listeners:{
        load: function( ths, records, successful, operation, eOpts ){
            debugger;
        }
    }
});

It doesn't work. The load event is never fired. No data is loaded. I can see that the proxy made the request, I see the response from the server, but it doesn't load.

If I put the proxy inline it loads.

var myStore = Ext.create('Ext.data.Store', {
    model: 'Test',
    proxy:{
       type: 'ajax',
       url : '../test',
       reader: {
         type: 'json',
         root: 'responseHeader'
       }
    },
    autoLoad: true,
    listeners:{
        load:function( ths, records, successful, operation, eOpts ){
         debugger;
        }
    }
});

I was thinking I could have one proxy, attach it to multiple stores, and just change the reader on it before I load the store.

like image 783
Jerinaw Avatar asked Aug 16 '12 18:08

Jerinaw


1 Answers

You are pretty much there, and although I'm pretty sure you are understanding it all, for the benefit of others allow me to give an extended answer and a slightly modified solution to your problem.

Definitions:

  • The Model - primarily defines the fields a record has.
  • A Store - holds a collection of records.
  • A Proxy - facilitates server communication through a chosen method (Ajax, Direct, etc.) and maps CRUD (Create/Read/Update/Destroy) operations when such result from a change in the associated store or model.
  • A Reader - Tells a proxy how to interpret the data the server returns.
  • A Grid or Combobox - can display store records.

You scenario is not an uncommon one - while by default ExtJS loads each store separately, it is likely an application would prefer various stores to be loaded at once through a single read call; for example, when rendering one store-dependent component is dependent on another store.

Your code is not far off from achieving this, but here is how I do it. In effect, when a 'master' (Tasks) store loads, the server response also carries the data of a 'slave' (Tags) store, which is then manually loaded to that 'slave' store.

The 'slave' store (notice autoload: false and no read operation):

Ext.define('DL.store.Tags', {
    extend: 'Ext.data.Store',    
    model: 'DL.model.Tag',

    // Notice the tags are actually returned when the tasks are loaded and loaded into this store by the TasksStore.
    autoLoad: false, 
    autoSync: true,

    proxy: {
        type: 'direct',

        api: {
            create:  Tags.Create,
            update:  Tags.Update,
            destroy: Tags.Destroy,
        },

        reader: {
            type: 'json',
            root: 'tags'
        }        
    },    

});

Then the 'master' store:

Ext.define('DL.store.Tasks', {
    extend: 'Ext.data.TreeStore',    
    model: 'DL.model.Task',

    autoLoad: true,   
    autoSync: true,

    root: {
        text: 'Root',
        id: null,
        expanded: true
    },

    proxy: {
        type: 'direct',

        api: {
            create:  Tasks.Create,
            read:    Tasks.Read,
            update:  Tasks.Update,
            destroy: Tasks.Destroy,
        },

    },

    onProxyLoad: function( aOperation )
    {
        // A read request for tasks will also return the user tags.
        // So feed these tags into their store.
        var iResult = aOperation.response.result,
            iTagsStore = Ext.StoreManager.lookup( 'Tags' );

        if ( Ext.isDefined( iResult.tags ) )
            iTagsStore.loadRawData( iResult );

        // We need this line for "Tasks" store to load its own data
        this.callParent(arguments);       
    }
});

Basically all it does is it takes part of the server response and loads it manually to the 'slave' store.

The PHP server side code (for tasks read operation) involves:

return array(
    'success'  => true,
    'children' => $iNodes,
    'tags' => $iTags            
);

Where children is the reader's root of the 'master' store, and tags is additional data that is then loaded into the 'slave' store.

I hope you can work how how to apply these concepts to your code.

like image 178
Izhaki Avatar answered Oct 25 '22 15:10

Izhaki