I one project I see :
initComponent: function() {
var me = this;
Ext.apply(me, {
items: [
{
xtype: 'stockform'
}
]
});
me.callParent(arguments);
}
What's this means? Tell me please.
I know Ext.apply() is used to simplify the copying of many properties from a source to a target object
var x = {a: 1, c:3, e:5};
Ext.apply(x, {b:2, d:4, f:6});
console.log(x); // Object {a: 1, b: 2, c: 3, d: 4, e: 5, f: 6}
It for applying given properties for given object.
In your case your componentn will be extending with property items which has internal component with type stockform. xtype is type shortcat.
Somwthere in ExtJs library OR in your project exists component with defined xtype stockform. Defining xtype stockform for component goes via adding property alias: "widget.stockform".
These are two questions in one, in fact:
What Ext.apply does?
What is an xtype?
Re 1: Ext.apply takes (usually) 2 objects as arguments: target and source and it copies all properties from the source object to the target object.
Re 2: xtype is a short name for a component (class), an alias. See "What is an xtype ... and other types" article for a detailed explanation.
Related
I've created a fiddle just to simulate my problem with class property not being reset on window destroy.
How to test:
Open fiddle, press OPEN button, ADD 3 panels, close ext window, press OPEN button again, and add a some more panels.
Panel numbers represent the length of the _panels array property in window.
Now to the problem.
As you can see panel NUMBER when adding new panels is not reset. So if you add 3 panels and close the window, reopen the window panels count shows 3 and then 4 and then 5 instead of 0 1 2 ...
My question is, why?
Fiddle example
Kind regards
Armando
EDIT : so one can see the solution
I ended fixing my application to work like this fiddle. I moved properties to constructor.
constructor: function() {
Ext.apply(this, {
width: 800,
height: 600,
layout: 'vbox',
_panels : []
});
this.callParent(arguments);
},
When you define
Ext.define('TestWindow', {
extend: 'Ext.window.Window',
_panel: []
});
The TestWindow definition class gets empty array property (no-primitive datatype). When you create an instance by var win = Ext.create('TestWindow'), the instance gets that property. However, when you set:
onDestroy: function() {
this._panels = [];
},
it sets empty array to property _panels of the instance win, not on the definition class TestWindow; TestWindow keeps the existing mutated _panel. And when next time you create new instance, it gets same _panel from class definition.
I understand you did it for demo purpose to show the problem. However, I prefer to let framework do all heavy-lifting (create and destroy etc):
Ext.define('TestWindow', {
extend: 'Ext.window.Window',
width: 800,
height: 600,
defaultListenerScope: true,
layout: 'vbox',
initComponent: function() {
this._panels = [];
this.callParent(arguments);
},
addPanel: function() {
console.log(this._panels.length);
var panels = this._panels;
panels.push(this.add({
xtype: 'panel',
title: 'Panel ' + panels.length,
height: 50,
width: '100%'
}));
},
tbar: [{
xtype : 'button',
text: 'add',
handler: 'addPanel'
}]
});
The simple answer for this is prototypal inheritance (see this MDN article). Basically your non-primitives will carry over to new instances because they exist on your prototype class, and because they're non-primitives, it's the same exact reference that's used. To fix this, I would recommend wrapping your _panels variable in the config block, like below, and encourage you to use the appropriate set/get methods, instead of accessing it directly:
config: {
_panels : []
}
A less than correct answer if the prototype behavior in the previous answer is "A feature/intentional bad code/ legacy code with unintended consequences"
Manually overwrite the prototype Value, following instantiation of the panel
For testing purposes, I made 2 views. One that requires the other view. Now I want people to be able to open components multiple times as a tab, so I obviously have to assign unique ID's to each tab and element inside of the component, right?
My question is, how can I access one of the root properties in a view from say the docketItems object?
In the code below, it will cause an undefined this.varindex error at id: 'accountSearchField' + this.varindex,. varindex is dynamically assigned from the other component. (I hardcoded it in the example code below)
Note that I will not know the exact ID, so I can not use something such as Ext.getCmp. I could make use of Ext.ComponentQuery.query('searchAccount') but perhaps there is a better way to do this?
Listed below is a portion of the code that is required by my main component.
Ext.define('cp.views.search.Account', {
extend: 'Ext.panel.Panel',
xtype: 'searchAccount',
varindex: "uniqueid_assigned_by_main_component",
listeners: {
beforerender: function(){
this.id = 'panelSearchAccount' + this.varindex
}
},
items: [
{
xtype: 'grid',
store: {
type: 'Account'
},
id: 'searchAccount' + this.varindex,
columns: [
///
],
dockedItems: [
{
xtype: 'fieldset',
items: [
{
id: 'accountSearchField' + this.varindex,
xtype: 'searchfield'
}
]
}]
}
]
});
Ext will generate IDs for DOM elements and ensure they are unique to the page, so it is unusual to use the id attribute for referencing components. There are two configuration properties with this purpose, itemId and reference.
There are multiple methods that can be used to acquire a component by itemId from a parent container or globally.
Ext.container.Container.getComponent
Ext.container.Container.query
Ext.container.Container.down
Ext.container.Container.child
Ext.ComponentQuery.query
Additionally, components can be acquired by Ext.app.Controllers using the refs configuration. These methods take a selector string. The selector for an itemId is the itemId prefixed with '#' (e.g. '#itemId'). You do not specify the '#' when configuring a component with an itemId.
Introduced along with support for MVVM in Ext JS 5, the reference identifier is unique to the component's container or ViewController. A component can be acquired by reference from components or ViewControllers using lookupReference. The lookupReference method takes only references as input and therefore, does not require a prefix.
If you want to be able to reference a component associated with a particular model instance (account), you can define the component class with an alias and configure the reference or itemId when you add each instance to the container.
for (var i = 0, ilen = accountModels.length; i < ilen; ++i) {
container.add({
xtype: 'accountpanel',
reference: accountModel[i].get('accountNumber')
});
}
In this example, an account's associated panel can be acquired later on using the account number.
var accountPanel = this.lookupReference(accountModel.get('accountNumber'));
Actually I may have figured it out. I simply moved the items inside of the beforerender event and made use of the this.add() function.
I have a question when defining 1 panel.
Ex1:
Ext.define('AppTest.view.AppMain', {
extend: 'Ext.panel.Panel',
xFile: "File",
// Init
initComponent: function () {
Ext.apply(this, {
items: [
{
xtype: 'button',
action: 'file',
text: this.xFile // Using variable here
}
]
});
this.callParent();
}
});
Ex2:
Ext.define('AppTest.view.AppMain', {
extend: 'Ext.panel.Panel',
xFile: "File",
items: [
{
xtype: 'button',
action: 'file',
text: this.xFile // Using variable at here
}
]
});
When I run 2nd Example, only Example 1 create "File" is text of button, and Example 2 just creating button, but "File" is not text of button.
Please help me explain the difference between the two ways of define, and how to use Example 2 still using this.xFile.
It is because of javascript closures. In first example this keyword refers to the defined object. ( here is your class instance). In simple words, you should find the closest function wrapper (here initComponent).
But in your second example, this refers to the window object which it has not xFile property. So it returns null. For test put the following line at the top of the second example and see the result :
this.xFile = 'hello!';
Finally I strongly recommend you to read in dept about closures and prototypes in javascript before coding complex scripts.
I want to use a very simple combo box in ExtJS, but I was surprised to learn that it seems as though I have to complexify things by using a store.
I have a single array of data :
var states = [
{"name":"Alabama"},
{"name":"Alaska"}
]
I create my model 'State' linking to the 'name' field, and then I create my store linking to the model, and the array of data.
Ext.regModel('State', {
fields: [
{type: 'string', name: 'name'}
]
});
var store1 = Ext.create('Ext.data.Store', {
model: 'State',
data: states
});
Now I create my combo, as a field in my panel :
var f = Ext.create('Ext.form.Panel', {
items: [
{
fieldLabel: 'hi there',
xtype: 'combobox',
name: 'XXXX',
store:store1,
maxLength: 64,
allowBlank: false
}
]
})
Nothing tells me that I am doing anything wrong, but I get an 'Uncaught TypeError: Cannot read property 'indexOf' of undefined ' whenever I try and open the combo.
My fiddle is here :
http://jsfiddle.net/sr61tpmd/1/
Another aside to my question is, what is the simplest way I can present a combobox in ExtjS?
As long as you only want a combo box with same value as displayed, it is entirely possible to define the store as an array.
xtype:'combo',
store:['Alabama','Arkansas',...]
A real extjs store is necessary where your displayed text differs from the value. You can see a working example for this (also using the us states, actually) in the ext docs: http://docs.sencha.com/extjs/4.2.2/#!/api/Ext.form.field.ComboBox
A lot of code examples use Ext.apply when setting properties on a component in the initComponent method.
Example :
initComponent: function(){
Ext.apply(this, {
items: {
xtype: 'button'
}
})},
My question is, what is the difference in doing it that way, compared to doing it this way :
initComponent: function(){
this.items = {
xtype: 'button'
}
}
For me it seems more readable that way. But am I missing something that I get from Ext.apply?
Ext.apply() is used to simplify the copying of many properties from a source to a target object (most of the time the source and target objects have different sets of properties) and it can in addition be used to apply default values (third argument).
Note that it will not make deep clones! Meaning if you have a array or a object as property value it will apply the reference!
There is also a applyIf() which only copies properties that do not already exist in the target object. In some cases both implementations have also the benefit of dropping the reference of the copied object.
Note:
Your second way won't work because you are missing this.
initComponent: function(){
items = {
xtype: 'button'
}
}
wouldn't initialize anything, you mean
initComponent: function(){
this.items = {
xtype: 'button'
}
}
which does the same like your example using Ext.apply. But Ext.apply shows its power in more complex cases, e.g.
var x = {a: 1, c:3, e:5};
Ext.apply(x, {b:2, d:4, f:6});
console.log(x); // Object {a: 1, b: 2, c: 3, d: 4, e: 5, f: 6}
This is often used to overwrite default options of components with given init parameters.