tags:

views:

3030

answers:

5

I'm trying to build application that use single config passed by server as non native JSON (can contain functions). Everything works fine so far but I'm curious why PagingToolbar does not have an option to use parent Grid store?

I have tried to set store in my config like this, but without success:

{...
   store:Ext.StoreMgr.lookup('unique_store_id')
}

Is there any way to do so without writing tons of javascript for each view defining store, grid and other items in my application or at least extend functionality of PaginationToolbar that use options from parent object?

UPDATED, Here is short example of server response (minified)

{
"xtype":"viewport",
"layout":"border",
"renderTo":Ext.getBody(),
"autoShow":true,
"id":"mainFrame",
"defaults":{"split":true,"useSplitTips":true},
"items":[
 {"region":"center",
 "xtype":"panel",
 "layout":"fit",
 "id":"content-area",
 "items":{
  "id":"manager-panel",
  "region":"center",
  "xtype":"tabpanel",
  "activeItem":0,
  "items":[
   {
    "xtype":"grid",
    "id":"domain-grid",
    "title":"Manage Domains",
    "store":{
     "xtype":"arraystore",
     "id":"domain-store",
     "fields":[...],
     "autoLoad":{"params":{"controller":"domain","view":"store"}},
     "url":"index.php"
    },
    "tbar":[...],
    "bbar":{
     "xtype":"paging",
     "id":"domain-paging-toolbar",
     "store":Ext.StoreMgr.lookup('domain-store')
    },
    "columns":[...],
    "selModel":new Ext.grid.RowSelectionModel({singleSelect:true}),
    "stripeRows":true,
    "height":350,
    "loadMask":true,
    "listeners":{
     "cellclick":activateDisabledButtons
    }
   }
  ]
 },
}
]
}
+1  A: 

The reason PagingToolbar is not linked to the Grid for its store is that a PagingToolbar can be used with any component that supports paging, not just a grid, so you have to explicitly assign a store to it (which could be a shared store that other components use too).

Not sure offhand why your code doesn't work -- I would assume that your lookup call must not be returning a valid store reference. The two obvious possibilities are that the id is wrong, or the store does not yet exist. Since you didn't post any other code, it's impossible to tell beyond that. BTW, you should be able to simply assign the store reference used by your grid directly to the toolbar without having to do a lookup, but I guess that depends on how your app is structured.

bmoeskau
I'm creating all elements by passing server response to Ext.ComponentManager.create({...}) with correct xtype. So most of elements are generated dynamically based on returned Object. In this case store defined inside Grid object and if necessary can be accessed via ID which does not work in my case, however in Firebug storage is accessible using this StoreMgr.lookup
Nazariy
Well, if you claim that the StoreMgr call is returning a valid store ref, then obviously something else is wrong in your code. Since you haven't posted any of your other config or app code, it's not possible to help you much further.
bmoeskau
here is returned server response.
Nazariy
+1  A: 

The config that you have gets executed whenever you define it - usually way before it is instantiated. So Ext.StoreMgr.lookup('domain-store') will happen before the grid constructor takes place.

This is a bit of a drawback of the way ext js uses static configs. What you need to do is to either override the grid and then programatically set the toolbar's store or perhaps use beforerender event on the grid like so:

//...grid config
listeners: {'beforerender' : {fn:function(){ this.getBottomToolbar().store = this.store }}}

EDIT: Changed bbar to getBottomToolbar().

Igor Zevaka
Thank you Igor for your example, but it does not work this way, for some reason items in tbar and bbar are not available directly via DOM. How ever I did managed to make it work via afterrender listerner and accessing bbar via this.getBottomToolbar()
Nazariy
Yep that would be right, I forgot that bbar is only a config property.
Igor Zevaka
+1  A: 

Another possibility is to create a subclass of GridPanel. The constructor of this subclass can examine its given config for a PagingToolbar config. If one is present, instantiate the store (if needed) and give a reference to it to the PagingToolbar config.

var MyGridPanel = Ext.extend(Ext.grid.GridPanel, {
    constructor: function( cfg ) {
        if ( cfg && cfg.store && cfg.bbar && cfg.bbar.xtype == 'paging'
            && ! (cfg.bbar instanceof Ext.PagingToolbar && ! this.bbar.store
        ) {
            if ( cfg.store.xtype && ! (cfg.store instanceof Ext.data.Store) ) {
                cfg.store = Ext.ComponentMgr.create(cfg.store);
            }

            cfg.bbar.store = cfg.store;
        }   

        MyGridPanel.superclass.constructor.call(this, cfg);
    }   
});

Example usage:

(new Ext.Window({
    width: 400,
    height: 200,
    layout: 'fit',
    items: new MyGridPanel({
        store: {
            xtype: 'arraystore',
            fields: ['name', 'value'],
            data: [ 
                ['name 1', 'value 1'],
                ['name 2', 'value 2']
            ]   
        },  
        columns: [
            {
                dataIndex: 'name',
                header: 'Name'
            },  
            {
                dataIndex: 'value',
                header: 'Value'
            }   
        ],  
        bbar: {
            xtype: 'paging',
            pageSize: 25
        }
    })
})).show();

Another option is to use createInterceptor to apply the above behavior to the GridPanel directly:

Ext.grid.GridPanel.prototype.initComponent =
    Ext.grid.GridPanel.prototype.initComponent.createInterceptor(function() {
        if ( this.store && this.bbar && this.bbar.xtype == 'paging'
            && ! (this.bbar instanceof Ext.PagingToolbar) && ! this.bbar.store
        ) {
            if ( this.store.xtype && ! (this.store instanceof Ext.data.Store) ) {
                this.store = Ext.ComponentMgr.create(this.store);
            }   

            this.bbar.store = this.store;
        } 
    });

This would allow you to continue using xtype: 'grid'.

owlness
Thank you Owlness for your example, It also might be a solution for my application. Is there any way I can overwrite default grid configuration to add extra validation for bottom toolbar.
Nazariy
Just had the biggest DOH!!! moment. I didn't realise you can put `constructor` as a function inside the object passed to `Ext.extend`. But of course it makes sense - constructor is just a function on the prototype and that's where all those functions go. All this time I have been defining the constructor as a function and then extending it. This way the code is much cleaner.
Igor Zevaka
What sort of extra validation are you asking about, Nazariy? Any manner of manipulation you would expect to be able to do to the config object can be performed in the constructor of the above example. More advanced modifications can also be applied through overriding of other methods or adding event listeners.
owlness
I meen would it work with Ext.apply() instead of Ext.extend()?
Nazariy
I have added an alternative technique to my answer which uses createInterceptor to modify GridPanel itself rather than create a subclass. Is that closer to what you are looking for?
owlness
A: 

I had the same problem, THANS Igor Zevaka, It works !!!!

John Smith
A: 

Actually on 3.2.0 the listnere didn't worked for me(it populated the grid, but it didn't let me change the page). The issue was that ext didn't know that it has to rebuild toolbar (as you just modified a variable). Fix bellow:

listeners: {'beforerender' : {fn:function(){ this.getBottomToolbar().bindStore(this.store ) }}},
Alexandru