extjs 4 XTemplate class associations
Asked Answered
U

6

11

I'm testing out extjs 4 and I have stumbled upon something, I can't seem to figure out.

I have simple object association: Snapshot - hasMany -> Model

Now, I am trying to use XTemplate to show this association in View component, so I have my XTemplate looking like this:

Ext.create('Ext.XTemplate',
'<tpl for=".">',
'<div class="snapshot" id="{id}">',
'<h1>{snapshot}</h1>',
'<p><span class="label">Created: </span>{dateString}</p>',
'<p><span class="label">Models</span></p>',
'<tpl for="models">',
'<p>{name}  - {description}</p>',
'</tpl>',
'</div>',
'</tpl>',
'<div class="x-clear bottompad"></div>'
);

And my JSON response looks like this (showing just 'snapshot' node):

    {
        "id": 1,
        "snapshot": "Snapshot 1",
        "created": 1305806847000,
        "models": [
            {
                "id": 1,
                "name": "ABC",
                "description": "A B C"
            }, {

                "id": 111,
                "name": "ABCDD",
                "description": "A B C XCXC"
            }
        ]
    }

As extjs 4 introduces concept of Model I have created models for Snapshot and Model and created association according to API docs.

Snapshot model:

Ext.define('Snapshot', {
    extend: 'Ext.data.Model',
    fields: [
        {name: 'id', type: 'int'},
        'snapshot',
        {name: 'created',type: 'date', dateFormat: 'time' }

    ],
    associations:[
      {type: 'hasMany', model: 'Model', name: 'models'}  
    ],
    idProperty: 'id'
});

Model model ;P

Ext.define('Model', {
    extend: 'Ext.data.Model',
    belongsTo: 'Snapshot',
    fields: [
        { name: 'id',  type: 'int' },
        { name: 'snapshot_id', type: 'int' },            
        'name',
        'description'
    ],
    idProperty: 'id'
});

And this is where my problem lies - When I use this setup, none of my models is displayed when XTemplate is being executed, however if I remove associations from Snapshot model and just add another field called 'models' it works OK.

What is the best practise to display list of models correctly while using associations? Would I have to use nested templates and custom functions to do this?

Ulphiah answered 24/6, 2011 at 12:39 Comment(0)
F
7

Good Question (+1)

It seems using the associations directly in the XTemplate is not possible (today) because XTemplate expects array of objects. (When you have associations, this is no longer true)

You have three options -

  1. Get rid of associations like you mentioned. (does not 'sound' good but will work)
  2. If you have a data view using the template, override Ext.view.AbstractView.prepareData and create array of objects from your models
  3. Before you call apply, iterate over the snapshotStore.getRange() and (re)generate objects with "models" attribute and pass this array to .apply
Flameproof answered 24/6, 2011 at 17:6 Comment(3)
This is kind of shooting in their own foot, I do like concept of ORM in sencha, most languages do have some kind of ORM by now and I can see this feature to be a solid block of their MVC concept, but I was honestly hoping for this to be working off-box. Maybe next release would bring this functionality. For now I think I'll stick to the models concept without associations as this will be least painfull transition model for my project.Ulphiah
I agree. Overall, lots of good things in ExtJS4 but it has failed miserably on the quality aspect. (even the documentation is incomplete and lot of articles just stop midway while explaining something) Looking at the sencha forum, "the lights are on but no one's at home". Anyhow, if this answer has helped you, consider upvoting or acceptingFlameproof
It might be worth noting for future browsers that the prepareData method (as of 4.1 beta2) now does use the getAssociatedData method and applies these to the data object returned.Thermostat
Q
3

I should point out that as of 4.1, a model record has a method called getData(), which if called using getData( true ) will also return the associated data.

Query answered 20/2, 2013 at 13:42 Comment(1)
And how does that help?Recuperator
M
2

I totally agree it would be ideal to have templates look like this. However, it's actually quite easy to get a template to do what you want with associations. Models hold all of their fields within a property called data and associations at the root level with the convention: associationName+'Store'. Therefore, all you need to do is write your template as follows:

var template = Ext.create('Ext.XTemplate',
    '<tpl for=".">',
        '<div class="snapshot" id="{data.id}">',
            '<h1>{data.snapshot}</h1>',
            '<p><span class="label">Created: </span>{data.created}</p>',
            '<p><span class="label">Models</span></p>',
            '<tpl for="modelsStore">',
                '<p>{data.name}  - {data.description}</p>',
            '</tpl>',
        '</div>',
    '</tpl>',
    '<div class="x-clear bottompad"></div>'
);
Multistage answered 7/3, 2013 at 20:51 Comment(1)
Try this instead '<tpl for="models"><p>{name} - {description}</p></tpl>',Coot
H
0

You can listen on the store.load event and add the associated data back to the store record, and then the template will work (I did this using the RowExpander's rowBodyTpl).

listeners: {
    load: function(store,storeRecs) {
        var i,r;
        for (i=0;i<storeRecs.length;i++) {
            r = storeRecs[i];
            r.data.subItem = r.getAssociatedData().subItem;
        }
    }
}
Hypertonic answered 15/7, 2011 at 14:19 Comment(0)
C
0

Like @Izhaki says use getData(true) on the record to pass the data to the template, then do a variation of what @Aaron says to loop thru the data. For example, if the template is part of a container:

 //...
 tpl: //your tpl
 data: record.getData(true)
 //....

This template snippet should work fine:

 '<tpl for="models">',
 '<p>{name}  - {description}</p>',
 '</tpl>'
Classics answered 24/4, 2013 at 15:4 Comment(1)
If you work with a store (you have more than one model) this doesn't work.Recuperator
P
-1

from my very recent experience, you shouldn't have problems if you are NOT working through stores. The XTemplate example from ExtJS 4 docs works ok (at least for me). You can add a model for those data and the example will be working on.

I tried to do the same through a store. When you pass the store.first().data to the overwrite(...) XTemplate method, the associations are not in that structure. You can check in the following code:

var data = {
    name : 'Tommy Maintz',
    title : 'Lead Developer',
    company : 'Sencha Inc.',
    email : '[email protected]',
    address : '5 Cups Drive',
    city : 'Palo Alto',
    state : 'CA',
    zip : '44102',
    drinks : ['Coffee', 'Soda', 'Water'],
    kids : [{
                name : 'Joshua',
                age : 3
            }, {
                name : 'Matthew',
                age : 2
            }, {
                name : 'Solomon',
                age : 0
            }]
};



var kidsModelProps = {
    extend: "Ext.data.Model",
    fields: [
        "name",
        {name: "age", type: "int"}
    ]
}
Ext.define ("KidsModel", kidsModelProps)

var datamodelProps = {
    extend: "Ext.data.Model",
    fields: [
        "name", "title", "company", "email", "address",
        "city", "state", "zip", "drinks"
    ],

    hasMany: {name: "thekids", model: "KidsModel"},

    proxy: {
        type: "memory",
        reader: {
            type: "json"
        }
    }
}
Ext.define ("DataModel", datamodelProps)


var kidsStore = new Ext.data.Store({
    data: data,
    storeId: "kidsStore",
    model: "DataModel"

})

var tpl = new Ext.XTemplate(
    '<p>Name: {name}</p>',
    '<p>Title: {title}</p>',
    '<p>Company: {company}</p>',
    '<p>Kids: ',
    '<tpl for="kids">',     // interrogate the kids property within the data
        '<p>{name}</p>',
    '</tpl></p>'
);

Ext.onReady(function () {
    var thePanel = Ext.create ("Ext.panel.Panel", {
        html: "<b>Viewport tpl-test: build with separated files</b>",
        border: 10,
        height: 500,
        layout: {
            type: 'vbox',
            align: 'center'
        },
        renderTo: Ext.getBody(),
        bodyStyle: "background-color: yellow",

        items: []

    })
    var someData = kidsStore.first().data
    tpl.overwrite (thePanel.body, someData)
}

You can also can try (to see how bad XTemplate-Store-Associations work) at http://www.sencha.com/forum/showthread.php?127320-FIXED-EXTJSIV-242-multiple-HasMany-association-conflict-in-XTemplate.

sorry not to provide a solution : (

w i l l y

Perfumer answered 11/8, 2011 at 16:16 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.