OK, let's start with this one:
Code:
Ext.define('AM.view.crafter.Block', {
extend: 'Ext.panel.Panel',
alias: 'widget.block',
config: {
id: 0
},
html: '<img src="images/'+this.getId+'.png" />'
});
The use of a config block is standard practice in Touch 2 but in ExtJS 4 I wouldn't go anywhere near it. It was half-baked in 4.0 and the attempts to fix it in 4.1 still fall short in my opinion.
This line cannot possibly work:
Code:
html: '<img src="images/'+this.getId+'.png" />'
The biggest problem here is that it is evaluated immediately, before Ext.define is even called. At that point the this reference will point to the global window object.
It's important to understand how config options end up on this. It isn't a JavaScript feature, it's something done by the framework. In the constructor for components (and some other types of class) there is a line Ext.apply(this, config); which copies the config onto the current object. Prior to running the constructor the config will not be copied across.
Components have a template method called initComponent that runs after this copying takes place. In general it is best practice to override this method rather than the constructor and to reference the properties via this rather than the config. This won't necessarily come naturally if you have a Java background, it took me a long while to stop mucking around in the constructor and just let things take their course.
Next up:
Code:
Ext.define('AM.view.crafter.Block', {
extend: 'Ext.panel.Panel',
alias: 'widget.block',
id: 0,
constructor: function(id) {
this.html = '<img src="images/'+id+'.png" />';
this.callParent(arguments);
}
});
As you correctly identified, the problem here is that you've put an id on the prototype so it will be shared between all instances. You should generally avoid using component ids at all. It isn't clear whether you're doing it on purpose or not but the property id has a special meaning and if you just wanted to pass through the image location I'd suggest using a different name for it.
Quite why you're extending Panel isn't clear. Panels are heavy-weight components and should only be used where necessary (e.g. if you need docked items such as headers or toolbars). For adding some simple HTML it's overkill.
A more Ext way of writing this might be:
Code:
Ext.define('AM.view.crafter.Block', {
extend: 'Ext.Component',
alias: 'widget.block',
initComponent: function() {
this.html = '<img src="images/' + this.imgId + '.png" />';
this.callParent();
}
});
You'd then create this using:
Code:
items: [
Ext.create('AM.view.crafter.Block', {imgId: '266'}),
Ext.create('AM.view.crafter.Block', {imgId: 'dec:30216'}),
Ext.create('AM.view.crafter.Block', {imgId: '266'})
]
or even better:
Code:
items: [
{xtype: 'block', imgId: '266'},
{xtype: 'block', imgId: 'dec:30216'},
{xtype: 'block', imgId: '266'}
]
You could throw in a defaultType too if you don't fancy typing all those xtypes.
To take this a little further, if you need to be able to change the image dynamically after creation then I'd use a tpl instead:
Code:
Ext.define('AM.view.crafter.Block', {
extend: 'Ext.Component',
alias: 'widget.block',
tpl: '<img src="images/{id}.png" />',
initComponent: function() {
this.callParent();
this.setImgId(this.imgId);
},
setImgId: function(id) {
this.update({id: id});
}
});
See the docs for tpl, data and update if you want to know more about what I'm doing here.