Can any tell me why i keep getting a method buildItems not defined in the following code ? Am i escaping something essential ?
Ext.define('MyApp.view.Viewport', {
extend: 'Ext.container.Viewport',
requires: [
'Ext.layout.container.Border'
],
layout : 'border',
items : [this.buildItems()],
buildItems : function() {
return { region:'center',xtype:'panel'}
}
});
The buildItems method has no reason to be a public method, i was only trying this way first. This is the way i'm doing it now:
(function() {
function buildItems () {
return [
{
region : 'center',
xtype : 'panel',
}, {
region : 'west',
xtype : 'panel',
width : 225
},{
region : 'south',
xtype : 'panel',
height : 50
},{
region : 'north',
xtype : 'panel',
height : 50
}
]
}
return Ext.define('MyApp.view.Viewport', {
extend: 'Ext.container.Viewport',
requires: [
'Ext.layout.container.Border'
],
layout : 'border',
items : buildItems()
});
})();
Is this an overstretch ?
thx
The problem is: At the time of execution of the line
items : [this.buildItems()],
the scope is the Global Object, i.e. this evaluates to window.
You should not put items into a class anyway, since the instances may modify the item's items, so the right way to do it is
initComponent: function () {
this.items = this.buildItems(); // now, "this" is the current component instance
// superclass.initComponent...
}
Edit: As an answer to the second part of the question
This has been discussed a million times, and there's nothing wrong with making that helper function private. I personally tend to keep methods public, since that increases readability of the code. Usually I use doc comments (#private) as a marker, and quite simply avoid calling supposedly private methods. I think this is not a big deal, since I'm mostly not building libraries or anything reusable for third-party developers.
It is because the function is defined in another function and the viewport will be accessed outside this self-executing function. So, put this buildItems() outside the self-executing function and try the same.
Related
I'm using ExtJS framework and a run one method multiple times with different parameters.
I'm looking a way to make it more consist, easy and maintainable and I guess just vanilla Javascript solutions could handle this?
I've tried to collect each param into array and using Array.map() as well forEach() methods but I couldn't handle it.
Thanks for advance.
//ExtJS class:
Ext.define('MyApp.FooClass', {
extend: 'Ext.panel.Panel',
items: [
MyApp.createFooCard('Func1Param1', 'Func1Param2', 'Func1Param3'),
MyApp.createFooCard('Func2Param1', 'Func2Param2', 'Func2Param3'),
MyApp.createFooCard('Func3Param1', 'Func3Param2', 'Func3Param3'),
]
});
As you'll notice I totaly use same method but different arguments for each of them.
//And here is related factory-function:
createFooCard: (bindValue, userCls, glyph, label) => {
return {
itemId: bindValue,
userCls: userCls,
glyph: MyApp.getGlyph(glyph),
items: {
xtype: 'infocardfld',
fieldLabel: label,
bind: '{' + bindValue + ' || "0"}'
}
}
}
It works with Array.prototype.map to collect nested arrays and relaying those arrays with Spread syntax to run on factory-function. It should be:
Ext.define('MyApp.FooClass', {
extend: 'Ext.panel.Panel',
items: [
['Func1Param1', 'Func1Param2', 'Func1Param3'],
['Func2Param1', 'Func2Param2', 'Func2Param3'],
['Func3Param1', 'Func3Param2', 'Func3Param3']
].map(args => MyApp.createFooCard(...args));
});
If this Items array is in the global scope you could easily add elements to it inside the createFooCard function. As a example:
// Your element collection array
var items = []
//Your function
function createFooCard(bindValue, userCls, glyph, label) {
var temp = {
itemId: bindValue,
userCls: userCls,
glyph: MyApp.getGlyph(glyph),
items: {
xtype: 'infocardfld',
fieldLabel: label,
bind: '{' + bindValue + ' || "0"}'
}
};
items.push(temp);
}
You could easily pass the array as a param as well. if you wants to make it more generalized.
I have a simple grid, which looks like so:
{
xtype: "grid",
columns: [{
header: 'Title', flex: 1, dataIndex: 'Title'
}],
store: Ext.create('Ext.data.Store', {
fields:['id', 'Title']
})
}
And I have a function (attached to a button) which, I believe, should populate this grid with some data. It does it like so:
grid.store.removeAll();
records = [{"id":"1", "Title", "Hello world"}];
grid.store.add(records);
grid.store.load();
console.log(grid.store.getCount());
But for some insane reason, the store is empty and grid.store.getCount() echoes "0". What the heck is going on? PS. I'm using ExtJS 6.
EDIT
If however I slightly change my code to this:
...
store: Ext.create('Ext.data.Store', {
autoLoad: false,
fields:['id','Title'],
data:[{"id": 1,"Title": "Hello world"}]
})
...
//and in function just one line of code:
grid.store.load();
then it starts working. So, it seems like the whole problem is with store.add. It does not do what it should.
Just remove grid.store.load().
The load marks the store as needing a load, but if your adding records using add that is not what you need.
Working example: https://fiddle.sencha.com/#fiddle/1fbv
I've got a Sencha Touch 2 view that's using this ratings class: Ext.ux.touch.rating, with two instances:
{
xtype: 'rating',
id: 'rating1',
value: -1,
itemCls: 'x-rating-star',
itemHoverCls: 'x-rating-star-hover',
listeners: {
change: function () {
Ext.getCmp('ratingBtn').setDisabled(Ext.getCmp('rating2').getValue() == -1)
}
}
},
...
{
xtype: 'rating',
id: 'rating2',
value: -1,
itemCls: 'x-rating-star',
itemHoverCls: 'x-rating-star-hover',
listeners: {
change: function () {
Ext.getCmp('ratingBtn').setDisabled(Ext.getCmp('rating1').getValue() == -1)
}
}
},
...
{
xtype: 'button',
ui: 'confirm',
text: 'Rate',
id: 'ratingBtn',
disabled: true
},
I'm trying, with the code above, to get ratingBtn (IDs are named slightly differently in my code) to be enabled once both ratings have been filled.
If I only have the first listener attached, things work fine (except no action on the second rating changing). If I attach the second listener with a console.log(this) or console.log(this.parent) or even Ext.getCmp('ratingBtn'), the app builds fine.
But if I attempt to invoke setDisabled() on the element (and this only happens for the second listener...and happens even if I call it as setDisabled(false)), I get this when compiling (plus a huge stack trace):
[ERROR] TypeError: 'undefined' is not an object
Stack trace:
file:////[snipped]/app/view/[snipped].js?_dc=1371009329838 : 346 : Anonymous
with line 346 being the line where I attempted to call setDisabled().
I can't find a way (including pushing both listeners to the controller) to get rid of this error, or one effectively identical to it. Even doing naughty things like document.getElementById return null, so the build tool says.
So, how do I fix this issue? I realize that the above code won't win any awards for OOP, but it should at least build...right?!? How do I get it to do that?
I have a grid.panel on the side with table names and I'd like to show the table(or it's structure) when the user clicks on it, in another grid.panel inside a tab view.
what i did:
in the actionlistener
var store = Ext.data.StoreManager.lookup('Tables');
currentTable = store.findRecord('name',record.get('name'));
var structureView = Ext.ComponentQuery.query('structure')[0];
structureView.showTable(currentTable);
in the view
showTable: function(table) {
this.storeObj.getProxy().url = '/tables/stucture/' + table.data.name;
this.storeObj.load();
this.update();
}
In the Tables store I have table descriptors, with some basic data like name, etc. and the list with table names displays the content of this store. So I look up the Tables store and get the tabledescriptor and pass it to the view, which then loads the store('Columns' in this case) with the data it will display. And all this works fine until I switch tabs. After changing the active tab and then changing back data is not refreshed on clicking on another table's name and I get this: Uncaught TypeError: Cannot call method 'removeChild' of null. It seems that it can't load the store anymore after changing the active tab. I found this issue on forums but I couldn't find a solution for it.
Do you have any ideas?
Thanks for your time.
Edit:
Ext.define('App.view.Table.Structure', {
extend: 'Ext.grid.Panel',
alias: 'widget.structure',
store: 'Columns',
width: 800,
storeObj: undefined,
initComponent: function () {
this.columns = [{
header: 'Column name',
dataIndex: 'name',
flex: 1
}, {
header: 'Position',
dataIndex: 'position',
flex: 1
}, {
header: 'Default value',
dataIndex: 'defaultValue',
flex: 1
}, {
header: 'Column type',
dataIndex: 'type',
flex: 1
}, ];
this.storeObj = Ext.StoreManager.lookup('Columns');
this.callParent(arguments);
}
Well I managed to solve it at last, but I don't really understand why this solved the problem. So this is what I did:
Every time I needed to update the Columns store(or the others) I looked it up
instead of just looking it up in the initcomponent.
Instead of calling update() method I called reconfigure()
Now it works like charm, but I don't see why update didn't do the trick and why I had to look up the store every time I wanted to call load() on it... So if someone could explain it I would be thankful.
If I have an application which contains panels created with Ext.create, and those panels have items which are created with both Ext.create and configuration objects, I get a panel whose interface is completely unclickable and doesn't respond to any interaction.
I've create a sample JSFiddle which illustrates the issue. Click the "TEST" button to see an example of this failure.
You can't do component creation at class definition time. That is, using Ext.create directly inside config object of Ext.define:
Ext.define('App.views.Panel1', {
id:'panel1',
extend:'Ext.Panel',
config:{
title: 'test',
layout:'card',
items:[
{
items:[
{
xtype: 'button',
text: 'TEST',
handler:function(){
Ext.getCmp('panel1').setActiveItem(Ext.getCmp('panel2'));
}
}
]
},
// not good
Ext.create('App.views.Panel2', {id:'panel2'})
]
}
});
Even if this would work, it would result in all instances of Panel1 sharing one Panel2 instance.
Instead you should do your component creation at initialization time:
Ext.define('App.views.Panel1', {
id:'panel1',
extend:'Ext.Panel',
config:{
title: 'test',
layout:'card',
items:[
{
items:[
{
xtype: 'button',
text: 'TEST',
handler:function(){
Ext.getCmp('panel1').setActiveItem(Ext.getCmp('panel2'));
}
}
]
}
]
},
initialize: function() {
this.add(Ext.create('App.views.Panel2', {id:'panel2'}));
this.callParent();
}
});
The initialize method is a good place to do any kind of extra work you want to do every time you create an instance of your component class. callParent is there because we override initialize of a parent class which might have some of its own logic in there which we want to keep.