PDA

View Full Version : store binding and view rendering



tonyx
30 Aug 2011, 4:44 PM
I'm a bit new to Ext Js 4 and trying to find my way around by re-creating the nested loading example application (http://docs.sencha.com/ext-js/4-0/#!/example/app/nested-loading/nested-loading.html) from scratch provided by Ext. Here is my viewport file and book SideBar file

viewport.js



Ext.define("Books.view.Viewport", {
extend: "Ext.container.Viewport",
layout: "fit",
items: {
xtype: 'panel',
border: false,
id : 'viewport',
layout: {
type: 'vbox',
align: 'stretch'
},
dockedItems: [
Ext.create("Books.view.Header"),
Ext.create("Books.view.book.Sidebar")
],
items: [
{
......


Sidebar.js



Ext.define("Books.view.book.Sidebar", {
extend: "Ext.view.View",
alias: "widget.booksidebar",
id: "sidebar",
dock: "left",
width: 180,
border: false,
cls: "sidebar-list",
selModel: {
deselectOnContainerClick: false
},
store: "Books",
itemSelector: ".product",
tpl: new Ext.XTemplate(
'<div class="sidebar-title">Books</div>',
'<tpl for=".">',
'<div class="product">{name}</div>',
'</tpl>'
)
});


The problem is, however, that sidebar is not rendered. And if I were to try to call this.getBookSideBar().refresh() in the controller, I get the following error in console


me.store is undefined

records = me.store.getRange(); ext-all-debug-w-comments.js (line 83524)



However, if I were to inline the sidebar within viewport.js, then everything works perfectly

viewport.js with sidebar inlined


Ext.define("Books.view.Viewport", {
extend: "Ext.container.Viewport",
layout: "fit",
items: {
xtype: 'panel',
border: false,
id : 'viewport',
layout: {
type: 'vbox',
align: 'stretch'
},
dockedItems: [
Ext.create("Books.view.Header"),
{
xtype: "dataview",
dock: "left",
width: 180,
border: false,
cls: "sidebar-list",
selModel: {
deselectOnContainerClick: false
},
store: "Books",
itemSelector: ".product",
tpl: new Ext.XTemplate(
'<div class="sidebar-title">Books</div>',
'<tpl for=".">',
'<div class="product">{name}</div>',
'</tpl>'
)
}
],
items: [
{
......


Why is this the case? How come I couldn't specify the store within the view file?



PS: The example itself uses this.getBookSideBar().bindStore(this.getBooksStore()); with no problem, but I was trying to understand why wouldn't it just use the store configuration inside the view itself

rstuart
30 Aug 2011, 7:49 PM
Without looking at the example you are referring to, a quick first guess is that the answer lies in the order things are created. In your first example, you are calling Ext.create straight away. For this to work, the store has to already be initialised and binded the the Books id by the StoreManager. If it isn't, this might cause problems. In your second example, your using a config object which means it won't be initialised until the viewport is rendered, possibly allowing the store to be created first.

tonyx
31 Aug 2011, 8:22 AM
Hm. even if I were to have
requires: { "Books.store.Books" } in the Sidebar.js file and Viewport.js, the problem still persist for some reason and would not show the items. Any ideas?

tonyx
31 Aug 2011, 1:07 PM
After much debugging, I verified that it is indeed a timing issue. It turns out that by specifying store in the view file itself, it is looked up before the store is registered with the store manager. The call stack is shown below



lookup(store="Books")
initComponent()
constructor(config=Object {})
callParent(args=[Object {}])
constructor(config=Object {})
Ext.DataView()
Viewport.js()


At this point, even though the requires config makes sure that it the books store has been loaded, it still has not been instantiated, resulting in undefined when looking up.

When the component is created inline, the call to lookup happens much much later.



lookup(store="Books")
initComponent()
callParent(args=undefined)
initComponent()
constructor(config=Object { xtype="grid", title="Users", store="Books", more...})
callParent(args=[Object { xtype="grid", title="Users", store="Books", more...}])
constructor(config=Object { xtype="grid", title="Users", store="Books", more...})
Ext.Panel()
(?)(c=Ext.grid.Panel(), a=[Object { xtype="grid", title="Users", store="Books", more...}])
instantiate()
instantiateByAlias()
alias()
create(component=Object { xtype="grid", title="Users", store="Books", more...}, defaultType="panel")
createComponent(config=Object { xtype="grid", title="Users", store="Books", more...}, defaultType=undefined)
lookupComponent(comp=Object { xtype="grid", title="Users", store="Books", more...})
prepareItems(items=[Object { xtype="grid", title="Users", store="Books", more...}], applyDefaults=true)
add()
add()
initItems()
callParent(args=undefined)
initItems()
initComponent()
callParent(args=undefined)
initComponent()
callParent(args=undefined)
initComponent()
constructor(config=Object { xtype="panel", border=false, id="viewport", more...})
callParent(args=[Object { xtype="panel", border=false, id="viewport", more...}])
constructor(config=Object { xtype="panel", border=false, id="viewport", more...})
Ext.Panel()
(?)(c=Ext.panel.Panel(), a=[Object { xtype="panel", border=false, id="viewport", more...}])
instantiate()
instantiateByAlias()
alias()
create(component=Object { xtype="panel", border=false, id="viewport", more...}, defaultType="panel")
createComponent(config=Object { xtype="panel", border=false, id="viewport", more...}, defaultType=undefined)
lookupComponent(comp=Object { xtype="panel", border=false, id="viewport", more...})
prepareItems(items=[Object { xtype="panel", border=false, id="viewport", more...}], applyDefaults=true)
add()
add()
initItems()
initComponent()
callParent(args=[])
initComponent()
callParent(args=[])
initComponent()
constructor(config=Object {})
callParent(args=[Object {}])
constructor(config=Object {})
Ext.Viewport()
(?)(c=Books.view.Viewport(), a=[])
instantiate()
alias()
create()
onBeforeLaunch()
(?)()
createSingle()
fire()
onDocumentReady(fn=function(), scope=Object { name="Books", controllers=Ext.util.MixedCollection, autoCreateViewport=true, more...}, options=Object { single=true})
fn()
triggerReady(force=true)
(?)()
require(expressions=["Ext.util.Point", "Ext.fx.Manager", "Ext.fx.Anim", 66 more...], fn=function(), scope=[Trial] Ext.Loader {}, excludes=[])
triggerReady(force=undefined)
refreshQueue()
refreshQueue()
onFileLoaded(className="Books.view.Viewport", filePath="app/view/Viewport.js")
(?)()
onLoadFn()




So how can I be sure that when I specify the store it has been properly loaded and instantiated? Is there like a convention that I'm not suppose to specify the store inside the view itself? Any explanation would be very appreciated.

rstuart
31 Aug 2011, 2:31 PM
You are meant to register all stores with their associated Controller which handles all initialisation. See the MVC guide for an example.

tonyx
7 Sep 2011, 11:53 AM
I see. thank you. Also I think xtype is exactly intended for this purpose. Lazy initialization and delayed rendering after stores already become available.