I'm having some problems binding selected data from a treepanel to a gridpanel.
When I select a node that is a leaf in the tree, I want its children to load in the bound grid below.
My solution to it is to load the entire store at once, then filter the results using the built-in functionality, but I have yet to produce the wanted results. One of the filters are producing what I want, but that's the only one (check the JSFiddle link) - and no errors are thrown.
I have created a demonstration at JSFiddle: http://jsfiddle.net/E3LPa/
I believe the problem is in this controller:
Ext.define('Exxica.controller.CalculationSidebar', {
extend: 'Ext.app.Controller',
models: [
'ResourceGroup',
'ResourceItem'],
stores: [
'ResourceGroups',
'ResourceItems'],
views: [
'ResourceItemsGrid',
'Debug'],
onTeCalculation_RightSidebar_TabPanel_ResourceGroupsSelect: function (model, selected, eOpts) {
var store = this.getStore("ResourceItems");
var item = selected[0];
if (item.get('leaf')) {
if (this.setFilter(item.get('id'), store)) store.reload();
}
},
setFilter: function (f, s) {
var fId = parseInt(f, 10);
console.log(s);
if (fId !== 0) {
s.clearFilter();
s.filter('group_id', fId);
return true;
} else {
return false;
}
},
init: function (application) {
this.control({
"#teCalculation_RightSidebar_TabPanel_ResourceGroups": {
selectionchange: this.onTeCalculation_RightSidebar_TabPanel_ResourceGroupsSelect
}
});
}
});
If anyone could help me figure out what I am doing wrong, that would be greatly appreciated.
Your sidebar class was reloading the store unnecessarily and that was probably screwing things up, try this code which has various fixes to remedy this:
Ext.define('Exxica.controller.CalculationSidebar', {
extend: 'Ext.app.Controller',
models: [
'ResourceGroup',
'ResourceItem'],
stores: [
'ResourceGroups',
'ResourceItems'],
views: [
'ResourceItemsGrid',
'Debug'],
loaded: false,
onTeCalculation_RightSidebar_TabPanel_ResourceGroupsSelect: function (model, selected, eOpts) {
var store = this.getStore("ResourceItems");
var item = selected[0];
if(!this.loaded)
{
store.load();
this.loaded = true;
}
if (item.get('leaf')) {
this.setFilter(item.get('id'), store);
}
else
{
this.setFilter(-1, store);
}
},
setFilter: function (f, s) {
var fId = parseInt(f, 10);
console.log(s);
if (fId !== 0) {
s.clearFilter();
s.filter('group_id', fId);
return true;
} else {
return false;
}
},
init: function (application) {
this.control({
"#teCalculation_RightSidebar_TabPanel_ResourceGroups": {
selectionchange: this.onTeCalculation_RightSidebar_TabPanel_ResourceGroupsSelect
}
});
}
});
Related
I'm new in extJS and i've been working in an app for some time.
My problem is that I have an app with an MVC architecture and as I instatiate the controller I declare de stores. But when I run this app in the browser, for some reason the controller is trying to get the store from my controller folder.
I have other controllers runing in my app and all of them looks for the store in the stores folder.
Does anyone have a clue about this issue?
Thanks
Ext.define('SGE.controller.staticData.AbstractController', {
extend: 'Ext.app.Controller',
requires: [
'SGE.util.Util'
],
stores: [
'Actors',
'staticData.Categories',
'staticData.Cities',
'staticData.Countries',
'staticData.Languages'
],
views: [
'staticData.AbstractGrid',
'staticData.Actors',
'staticData.Categories',
'staticData.Cities',
'staticData.Countries',
'staticData.Languages'
],
init: function(application) {
this.control({
"staticdatagrid": {
render: this.render,
edit: this.onEdit
},
"staticdatagrid button[itemId=add]": {
click: this.onButtonClickAdd
},
"staticdatagrid button[itemId=save]": {
click: this.onButtonClickSave
},
"staticdatagrid button[itemId=cancel]": {
click: this.onButtonClickCancel
},
"staticdatagrid button[itemId=clearFilter]": {
click: this.onButtonClickClearFilter
},
"staticdatagrid actioncolumn": {
itemclick: this.handleActionColumn
},
"citiesgrid button[itemId=clearGrouping]": {
toggle: this.onButtonToggleClearGrouping
}
});
this.listen({
store: {
'#staticDataAbstract': {
write: this.onStoreSync
}
}
});
if (!Ext.getStore('countries')) {
Ext.create('SGE.store.staticData.Countries');
}
if (!Ext.getStore('languages')) {
Ext.create('SGE.store.staticData.Languages').load();
}
if (!Ext.getStore('actors')) {
Ext.create('SGE.store.staticData.Actors');
}
if (!Ext.getStore('categories')) {
Ext.create('SGE.store.staticData.Categories');
}
},
onStoreSync: function(store, operation, options){
Packt.util.Alert.msg('Success!', 'Your changes have been saved.');
console.log(store);
console.log(operation);
console.log(options);
},
render: function(component, options) {
component.getStore().load();
if (component.xtype === 'citiesgrid' && component.features.length > 0){
if (component.features[0].ftype === 'grouping'){
component.down('toolbar#topToolbar').add([
{
xtype: 'tbseparator'
},
{
xtype: 'button',
itemId: 'clearGrouping',
text: 'Group by Country: ON',
iconCls: 'grouping',
enableToggle: true,
pressed: true
}
]);
}
}
},
onEdit: function(editor, context, options) {
context.record.set('last_update', new Date());
},
onButtonClickAdd: function (button, e, options) {
var grid = button.up('staticdatagrid'),
store = grid.getStore(),
modelName = store.getProxy().getModel().modelName,
cellEditing = grid.getPlugin('cellplugin');
store.insert(0, Ext.create(modelName, {
last_update: new Date()
}));
cellEditing.startEditByPosition({row: 0, column: 1});
},
onButtonClickSave: function (button, e, options) {
button.up('staticdatagrid').getStore().sync();
},
onButtonClickCancel: function (button, e, options) {
button.up('staticdatagrid').getStore().reload();
},
onButtonClickClearFilter: function (button, e, options) {
button.up('staticdatagrid').filters.clearFilters();
},
handleActionColumn: function(column, action, view, rowIndex, colIndex, item, e) {
var store = view.up('staticdatagrid').getStore(),
rec = store.getAt(rowIndex);
if (action == 'delete'){
store.remove(rec);
Ext.Msg.alert('Delete', 'Save the changes to persist the removed record.');
}
},
onButtonToggleClearGrouping: function (button, pressed, options) {
var store = button.up('citiesgrid').getStore();
if (pressed){
button.setText('Group by Country: ON');
store.group('country_id');
} else {
button.setText('Group by Country: OFF');
store.clearGrouping();
}
}
});
Browser response
enter image description here
An ExtJs Controller pulls in the specified store files before rendering its UI. Assuming that you have not created any store files (assumption form your init function where you created the store if they do not exist), it first searches the store files to load them into the memory.
Another possible problem may be the store has a different namespace than that of the application, you will need to specify the full class name as well as define a path in the Loader's paths config or setPath method.
Refer doc ExtJs Controller's Stores.
I have a store in ViewModel like:
Ext.define('MyApp.page.PageModel', {
extend: 'Ext.app.ViewModel',
//...
stores: {
Posts: {
model: //...
}
}
});
And a grid like:
Ext.define('MyApp.page.MainView', {
extend: 'Ext.panel.Panel',
//...
initComponent: function () {
var me = this;
//...
me.items = [
{
xtype: 'grid',
bind: {
store: '{Posts}'
},
columns: [ /* ... */ ],
viewConfig: {
getRowClass: function (record) {
//...
}
}
}
];
me.callParent(arguments);
}
});
How can I change grid view AFTER store load (in my case)?
I tried to use mon and addManagedListener methods in grid events (beforerender and viewready) and I tried to use on and addListener methods to store inside those grid events, but this solution is not working.
Does someone have any ideas?
I'm using override for Ext.view.AbstractView, just to clear emptyEl and viewEl before store load event
store.on('beforeload', function() {
me.clearEmptyEl();
me.clearViewEl();
});
Here is my complete override
Ext.define('Ext.overrides.view.AbstractView', {
override: 'Ext.view.AbstractView',
onBindStore: function(store, initial, propName) {
var me = this;
me.setMaskBind(store);
// After the oldStore (.store) has been unbound/bound,
// do the same for the old data source (.dataSource).
if (!initial && propName === 'store') {
// Block any refresh, since this means we're binding the store, which will kick off
// a refresh.
me.preventRefresh = true;
// Ensure we have the this.store reference set correctly.
me.store = store;
me.bindStore(store, false, 'dataSource');
me.preventRefresh = false;
}
store.on('beforeload', function() {
me.clearEmptyEl();
me.clearViewEl();
});
}
});
In ExtJS 6, a function setEmptyText is available on the grid that will do this for you:
initComponent: function () {
var me = this;
//...
me.callParent(arguments);
me.getStore().on('load', function() {
me.setEmptyText(...);
})
}
In ExtJS 5, you have to do on your own:
me.getStore().on('load', function() {
var emptyText = 'Test empty text';
me.getView().emptyText = '<div class="' + me.emptyCls + '">' + emptyText + '</div>';
me.getView().refresh();
})
Relevant fiddle, will load its store 3 seconds after rendering.
I am creating a itemclick event of chart series items in extjs
"mychart series": {
itemclick: function() {
alert('s');
}
}
The above function does not work.
Chart series is not a Component, and so the selector never matches. You need to relay Series events as if they were fired by the Chart itself, and match against the Chart:
Ext.define('My.Chart', {
extend: 'Ext.chart.Chart',
alias: 'widget.mychart',
initComponent: function() {
var me = this;
me.callParent();
me.series.each(function(s) {
// This will relay Series `itemclick` event
// as `seriesitemclick` fired on the Chart itself
me.relayEvents(s, ['itemclick'], 'series');
});
}
});
Ext.define('My.Controller', {
extend: 'Ext.app.Controller',
init: function() {
this.control({
mychart: {
seriesitemclick: this.onSeriesItemClick
}
});
},
onSeriesItemClick: function(item) {
var sprite = item.sprite,
series = item.series,
record = item.storeItem,
value = item.value;
...
}
});
I am working on MVC Pattern.
I have two function bellow, one is working and the other is not working. Take a look at my controller code;
Ext.define('MyApp.controller.program', {
extend: 'Ext.app.Controller',
stores: [
'program'
],
deleteWithConfirm: function(button, e, options) {
var viewList = Ext.ComponentQuery.query('#programGrid')[0];
var selection = viewList.getSelectionModel().getSelection()[0];
if(selection)
{
Ext.MessageBox.confirm('Confirm', 'Are you sure you want to do that?',
function(btn, text ) {
if(btn == 'yes') {
console.log('yes clicked');
this.getProgramStore().remove(selection); //console error message: "TypeError: this.getProgramStore is not a function"
this.getProgramStore().sync();
}
if(btn == 'no') {
console.log('no clicked');
}
}
);
}
},
justDelete: function(button, e, options) {
var viewList = Ext.ComponentQuery.query('#programGrid')[0];
var selection = viewList.getSelectionModel().getSelection()[0];
if(selection)
{
this.getProgramStore().remove(selection);
this.getProgramStore().sync();
}
},
init: function(application) {
this.control({
"#tombolHapusProgram": {
click: this.deleteWithConfirm //this is not working
//click: this.justDelete //this is working
}
});
}
});
justDelete function is working good. But when I modify that code, adding a message box confirm, the code is not working even though I defines store.
Would you please show me how to solve this problem?
You need to set the scope for the callback:
Ext.Msg.confirm('A', 'B', function() {
}, this);
Your store instance is bound to the grid anyways so just do the following:
viviewList.getStore().remove(selection)
I am new to extjs.I want to associate a store on selecting a menu item from Ext.menu.Menu. I am using extjs 4.1.0. I searched on the net even went through sencha doc but I couldn't find any way to achieve this.
Is there some way to achieve it?
Thanks in advance.
I'm using a menu with a store in a project. Here's an example:
Ext.define("Ext.ux.menu.DynamicMenu", {
extend: "Ext.menu.Menu",
alias: 'widget.dynamicmenu',
loaded: false,
loadMsg: 'Loading...',
store: undefined,
icon: '',
constructor: function (config) {
var me = this;
Ext.apply(me, config);
me.callParent();
},
initComponent: function () {
var me = this;
me.callParent(arguments);
me.on('show', me.onMenuLoad, me);
listeners = {
scope: me,
load: me.onLoad,
beforeload: me.onBeforeLoad
};
me.mon(me.store, listeners);
},
onMenuLoad: function () { var me = this; if (!me.store.loaded) me.store.load(); },
onBeforeLoad: function (store) { this.updateMenuItems(false); },
onLoad: function (store, records) { this.updateMenuItems(true, records); },
updateMenuItems: function (loadedState, records) {
var me = this;
me.removeAll();
if (loadedState) {
me.setLoading(false, false);
Ext.Array.each(records, function (record, index, array) {
me.add({
text: record.get('DisplayName'),
data: record,
icon: me.icon
});
});
me.store.loaded = true;
}
else {
me.add({ width: 75, height: 40 });
me.setLoading(me.loadMsg, false);
}
me.loaded = loadedState;
}
});
I found this one on the sencha forums if IIRC, but can't find the link anymore. I made some tweaks for icons etc, ...
On the Ext.Array.each(records, ....
You'll need to define your own logic, It's depending on your model. My model has a DisplayName which I use to show as text. I also stock my record in a data property I made in the menu item. You're completely free there.
Good luck!