Access statics from this? - extjs

I have the following class in ExtJS 5.1:
Ext.define('Web.view.guard.apps.conexao.Conexao', {
extend: 'Web.view.guard.apps.App',
width: 400,
height: 600,
statics: {
title: 'Conexão',
icon: 'https://upload.wikimedia.org/wikipedia/commons/a/ac/Approve_icon.svg'
},
});
I want to access the static attributes from the instance context, like title = this.statics.title or something like this, from the controller or the view itself, but I can't find a way in the documentation.
I found through Google a reference to a method statics(), but it doesn't work, this.statics().title returns null, although the statics() method do exists.
How is it possible?

The simple way is
Web.view.guard.apps.conexao.Conexao.title
But this.self is a reference to Web.view.guard.apps.conexao.Conexao, so you can use this.self.title. See http://docs.sencha.com/extjs/5.1/5.1.1-apidocs/#!/api/Ext.Base-property-self and https://fiddle.sencha.com/#fiddle/na0
Ext.define('Web.view.guard.apps.conexao.Conexao', {
extend: 'Web.view.guard.apps.App',
width: 400,
height: 600,
statics: {
title: 'Conexão',
icon: 'https://upload.wikimedia.org/wikipedia/commons/a/ac/Approve_icon.svg'
},
myInstanceMethod: function() {
console.log(this.self.title);
}
});
var conn = new Web.view.guard.apps.conexao.Conexao();
conn.myInstanceMethod();
// 'Conexão'
// 'https://upload.wikimedia.org/wikipedia/commons/a/ac/Approve_icon.svg'
If you want it to be accessible to subclasses, be sure to use inheritableStatics: {} instead.

Related

EXTJS 6.7 - class properties not cleared on destroy

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

extjs - How to define a window as unique ?

Is there a way to define a window as unique ?
What I mean exactly is: when the window is already open, I want it to get focus, instead of opening it again.
For now my menu click event just does:
onMenuItemClick: function(){
Ext.create('Mb.view.UniqueWindow').show()
},
Give it a unique id, then verify if it already exists before creating it, otherwise just show it, something like
function onMenuItemClick() {
var wnd = Ext.getCmp('myUniqueWindow');
if (!wnd) {
wnd = Ext.create('Ext.window.Window', {
id: 'myUniqueWindow',
title: 'Unique Window',
height: 200,
width: 400,
layout: 'fit',
closeAction: 'hide', // This is really important otherwise closing it will destroy the window!
items: { // Let's put an empty grid in just to illustrate fit layout
xtype: 'grid',
border: false,
columns: [{
header: 'Hello World'
}], // One header just for show. There's no data,
store: Ext.create('Ext.data.ArrayStore', {}) // A dummy empty data store
}
});
} else {
wnd.getEl().highlight()
}
wnd.show();
}
You can see a working sample here
Save a reference to it:
if (!MyApp.someWin) {
MyApp.someWin = new Ext.window.Window();
}
MyApp.someWin.show();

Sencha opposite of Ext.getCmp('mainpage').add({items:stuff});

I have used the following to add content to my view:
Ext.getCmp('mainpage').add({items:thecarousel});
thecarousel is an array representing my carousel and its content. This all works as I require it to. Here's the code for it:
var thecarousel = {
xtype: 'carousel',
width: '100%',
height: '100%',
itemId: 'thecarousel',
id: 'carousel',
defaults: {
styleHtmlContent:true,
},
items: allcharts,
}
Ext.getCmp('mainpage').add({items:thecarousel});
Ext.Viewport.setMasked(false);// remove loading message`
What I am looking for is an method to do the opposite of this and remove the carousel from the view.`
I have unsuccessfully tried the following:
Ext.getCmp('mainpage').remove('carousel',false)
Ext.getCmp('mainpage').remove({items:'carousel'})
Ext.getCmp('mainpage').remove('carousel',true)
If you are using id: 'carousel', you can do that like this:
Ext.getCmp('mainpage').remove(Ext.getCmp('carousel'))
You could also do it using a component query:
var main = Ext.getCmp('mainpanel');
main.remove(main.down('#carousel'));//added missing closing brackets
//OR, if there is only one component of xtype 'carousel' on your mainpanel:
main.remove(main.down('carousel'));
I personally would avoid using IDs and go with the second method (you could give the carousel an itemId: 'carousel' and still use main.remove(main.down('#carousel')) if you want).

Calling this.callParent inside of Ext.js store.each

I have a Sencha class that extends Ext.draw.Component and it accepts a store of MyModel. I am trying two different methods and I am getting differing, non-satisfactory results.
The First Method
Inside the constructor of the class I read in the store and do the following:
//Inside constructor of the class
this.store = config.store; //config is passed in from the constructor
var me = this;
me.store.each(function (model) {
me.renderTo = model.get('elementToRenderTo');
me.items = [{
type: 'rect',
x: 1.6620979,
y: 52.362183,
radius: 90,
width: 448.10959,
height: 1000,
fill: model.get('color'),
stroke: 'none'
}];
if (me.items) {
Ext.apply(config, { //config is passed in from the constructor
items: me.items
});
}
me.callParent([config]);
}
When I put the last of the code where it is (inside of the store.each), I get an exception:
Uncaught TypeError: Cannot call method 'apply' of undefined
The Second Method
However, if I move the Ext.apply and callParent outside of the store.each, I don't get an expection, but only the last model gets drawn (likely because the me.items is being overwritten on each iteration of the model).
//Inside constructor of the class
this.store = config.store; //config is passed in from the constructor
var me = this;
me.store.each(function (model) {
me.renderTo = model.get('elementToRenderTo');
me.items = [{
type: 'rect',
x: 1.6620979,
y: 52.362183,
radius: 90,
width: 448.10959,
height: 1000,
fill: 'black',
stroke: 'none'
}];
}
if (me.items) {
Ext.apply(config, { //config is passed in from the constructor
items: me.items
});
}
me.callParent([config]);
Is there another way to create a custom Ext.draw.Component that uses a store? What am I missing? The second method doesn't seem right, but I can't get rid of the exception on the first.
There are a few possible issues with this code:
1
this.store = config.store;
Is this the store instance or a string config? The proper way to deal with store configs in a constructor is like so:
this.store = Ext.data.StoreManager.lookup(this.store || 'ext-empty-store');
2
Although you are using me for scope, you probably want to ensure that the scope of each is indeed that of what's outside it so:
me.store.each(function (model) { ... }, this);
3
Regardless of where you do this, you won't be pushing all of the items:
Ext.apply(config, {
items: me.items
});
Because what you do here is you keep override item with me.items.
You shouldn't apply anything to items - it's an array managed by the component itself. You should really add items to it instead:
items.push( me.items )
4
Are you assuming local store only? Because if your store is to be loaded asynchronously - you'd get nothing unless you load the items upon load.
5
What are you actually trying to do here? Have the items loaded from a store? If such is the case you shouldn't do it in the constructor.
You should really look at one of the Ext source files to see how this is to be done. Here's a simplified version of how Ext.panel.Table does it:
Ext.define('Ext.panel.Table', {
extend: 'Ext.panel.Panel',
initComponent: function() {
var me = this,
store = me.store = Ext.data.StoreManager.lookup(me.store || 'ext-empty-store');
me.mon(store, {
load: me.onStoreLoad,
scope: me
});
},
onStoreLoad: function() {
}
});

change the background color of panels in extjs

In my project, I am trying to change the background color of all the panels inside a container. The code which I am trying is as follows:
container --> panel (don't change) --> panel (Change)
//Generated dynamically using for loop.
listeners: {
'render': function(panel) {
panel.body.on('click', function() {
//here change the background color of all the panels inside the container>panel.
});
}
}
What should I write to change the background color of the only panels which are present inside the parent panels of a main container?
I tried:
Ext.each('panel',function(){this.body.setStyle('background','white')}),
But the above approach is giving me the following error:
Uncaught TypeError: Cannot call method 'setStyle' of undefined
EDIT:
Here, I am looking for a method of extjs which quite do the same work as jQuery's children().
$('#containerID').children('panel').children('panel').css(change background color);
Based on your requirements you will always have a sum of 9 components you are looking at -1 the you start from. The shortest way is to use the each() method of the MixedCollection (at runtime all items are within a MixedCollection)
'render': function(panel) {
panel.body.on('click', function() {
panel.items.each(function(p){ p.body.setStyle('background','white'); }, this)
},this);
}
This may not be the variant with the best performance but knowing your requirement from the last question I can say that this is the easiest. And in addition it will be easy to maintain. And read the article about delegates that I posted in the comments of the last question!
I hope there is now typo, cause it is untested
Update
Well, you are looking for the ownerCt property here (at least that is the easiest way). But there are some mightier navigation methods up() / down() both can be feeded with a ComponentQuery string. Leave the up() arguments empty will return the immediate owner/activater (basically the same as ownerCt).
Following a working example:
var childItems = [], items = [];
for (i = 0; i < 9; ++i) {
childItems.push({
xtype: 'container',
width: 50,
height: 50,
html: i + '',
style: {borderColor:'#000000', borderStyle:'solid', borderWidth:'1px'},
listeners: {
'afterrender': function(panel) {
panel.el.on('click', function(e,t) {
panel.el.on('click', function(e,t) {
panel.el.setStyle('background','red');
panel.ownerCt.items.each(function(p){ if(panel.el.id != p.id) p.el.setStyle('background','white'); })
});
}
}
});
}
for (i = 0; i < 9; ++i) {
items.push({
xtype: 'container',
layout: {
type: 'table',
columns: 3
},
style: {borderColor:'#000000', borderStyle:'solid', borderWidth:'1px'},
items: childItems
});
}
Ext.create('Ext.container.Container', {
layout: {
type: 'table',
// The total column count must be specified here
columns: 3
},
renderTo: Ext.getBody(),
style: {borderColor:'#000000', borderStyle:'solid', borderWidth:'1px', margin: '30px'},
items: items
});
Update 2
To reset all try this (untested)
'afterrender': function(panel) {
panel.el.on('click', function(e,t) {
panel.el.setStyle('background','red');
panel.ownerCt.ownerCt.items.each(function(op){
op.items.each(function(p){
if(panel.el.id != p.id)
p.el.setStyle('background','white');
})
}, this)
});
}
JSFiddle

Resources