extjs combobox does not update after store load - combobox

In my MVC application I have a controller defined like this:
Ext.define('NE.controller.MyController', {
extend: 'Ext.app.Controller',
stores : [...'StoreAgents'..],
views: [ ...'MyView'...], // * alias w_view
init: function() {
this.control({
'w_view': {
render: function() { this.getStore('StoreAgents').load(); }
}
});
}
});
And in the view MyView I have a combobox defined like this:
{
xtype: 'combobox',
name : 'id_agent',
forceSelection: true,
fieldLabel: 'Agent',
store: 'StoreAgents',
queryMode: 'local',
displayField: 'name',
valueField: 'id'
}
I would expect combobox list to be updated every time the view is rendered, am I wrong?
Currently the combobox remains with no options, even if I see (through firebug) that the application fires the request which correctly returns all agents data.
Furthermore, I noticed that whenever I browse through another view, managed by another controller, which in turn declares another StoreAgent and calls its load() method.. well, if I come back, now I see the combobox populated.
What I am missing?
Thank you
Edit:
I noticed that the store is {buffered: true}. If I switch it to false, then the store fires the 'datachange' event; otherwise it does not. So the question now is: why if buffering is enabled the load() does not fire 'datachange'?

This may be due to a filtered out situation. If the combobox is being filled with a value before the store loads, a filter will be put on the store that filters out all the values before they exist, and then when new records are added they are not displayed either. Try this.
init: function() {
this.control({
'w_view': {
render: function() { this.getStore('StoreAgents').load();
this.getStore('StoreAgents').clearFilter();}
}
});
}

Related

extjs contextmenu click error - method not found... but looking in wrong controller

how do I point this menu item click to launch a method in a controller.
The item click is being hit successfully but the error message states No method named "onDownloadTopdayRecapContextButton" on ExtApplication4.view.main.MainController. That is the problem, you can see the view's controller is portalRealtime-portalRealtime.
So somehow its pointing to the wrong controller. Can someone show me what I am doing wrong?
menu code
var contextMenuTopday = Ext.create('Ext.menu.Menu', {
items: [{
text: 'Download Topday Recap',
iconCls: 'downloadIcon',
listeners: {
click: 'onDownloadTopdayRecapContextButton'
}
grid menu is held in
Ext.define('ExtApplication4.view.portalRealtime.PortalRealtime', {
extend: 'Ext.panel.Panel',
xtype: 'app-portalRealtime',
itemId: 'portalRealtimeItemID',
requires: [
'ExtApplication4.view.portalRealtime.PortalRealtimeController',
'Ext.form.action.StandardSubmit'
],
controller: 'portalRealtime-portalRealtime',
title: 'Main Portal',
layout: {
type: 'vbox'
},
items: [
//i deleted some grid code here
collapsible: true,
collapseDirection: 'left',
listeners: {
itemcontextmenu: function (view, rec, node, index, e) {
e.stopEvent();
contextMenuTopday.showAt(e.getXY());
return false;
}
{
You are creating the context menu outside of your view, so it does not inherit your controller.
Before using the below code please scroll to the bottom of the answer for a better solution, but this hopefully shows what is the cause of your issue.
If this doesn't solve your issue, please comment and provide a more complete code example, and I will update my answer
In these cases you can pass a controller manually, but you need to pass as a parent, as you get all kinds of problems if you re-use the same controller on multiple components (when you destroy one for example, it destroys the controller, leaving the other without)
So you could create from within your view like so:
Ext.define('ExtApplication4.view.portalRealtime.PortalRealtime', {
initComponent:function(){
this.callParent(arguments);
this.contextMenuTopday = Ext.create('Ext.menu.Menu', {
controller:{
parent: this.getController()
},
items: [{
text: 'Download Topday Recap',
iconCls: 'downloadIcon',
listeners: {
click: 'onDownloadTopdayRecapContextButton'
}
}]
});
}
Then rather than use a variable to access the context menu you can access the contextMenuTopday property, as you are within a child item you may need to traverse to your actual view, the simplest way of doing this is via the up method available on components, you would need to make sure you include an xtype to do this:
Ext.define('ExtApplication4.view.portalRealtime.PortalRealtime', {
xtype:'portalrealtime'
Then from within the context menu you can do:
itemcontextmenu: function (view, rec, node, index, e) {
this.up('portalrealtime').contextMenuTopday.showAt(e.getXY());
}
A better way
Best illustrated looking at this fiddle: https://fiddle.sencha.com/#view/editor&fiddle/1qpn
Define your menu as its own class:
Ext.define('Example.ContextMenu', {
xtype:'testmenu',
extend:'Ext.menu.Menu',
items: [{
text: 'Download Topday Recap',
iconCls: 'downloadIcon',
listeners: {
click: 'onDownloadTopdayRecapContextButton'
}
}]
});
Use a method on your controller for the itemcontextmenu event (This is good anyway as it provides a better separation of concerns):
itemcontextmenu: 'showContextMenu'
Then add a a few new methods to your portalRealtime-portalRealtime controller:
getContextMenu:function(){
if(!this.contextMenu){
this.contextMenu = this.getView().add({xtype:'testmenu'});
}
return this.contextMenu;
},
showContextMenu:function (view, rec, node, index, e) {
// we can't use showAt now we have added this to our view, as it would be positioned relatively.
this.getContextMenu().show().setPagePosition(e.getXY());
}
What we are doing here is adding the context menu to the view, so it inherits the controller (and a viewmodel if provided).
The best way to call methods on your controller for listeners/button handlers etc is to just specify the method name as a string i.e.:
listeners:{
itemcontextmenu: 'showContextMenu'
}
This will automatically look up the responsible controller and use the correct method.
If you need to call from within a component you will find that this.getController() fails unless you call on the actual component the controller is attached to - i.e. you are calling from a child component. In these cases you can use this.lookupController() to find the inherited/responsible controller and then call any methods from here e.g. this.lookupController().myMethod()

extjs 5 Error while setting value to the combobox with remote values

Having form panel with combo box in it
Ext.define('MyApp.admin.view.UserAddView', {
extend: 'Ext.form.Panel',
requires: [
'MyApp.admin.controller.UserAddViewController'
],
controller: 'userAdd',
autoScroll: true,
frame:true,
items: [{
xtype:'combobox',
fieldLabel: 'Roles',
collapseOnSelect: true,
editable: false,
multiSelect: true,
queryMode: 'remote',
queryParam: undefined,
displayField: 'authority',
bind: {
store: '{role}'
},
name: 'authorities'
}]
});
Then I want to set values dynamically to this combobox from the view controller
var ob = {'authorities': 'ROLE_ADMIN_USERS'};
var panelToAddName = Ext.create('MyApp.admin.view.UserAddView', {});
panelToAddName.getForm().setValues(ob);
Every time I receive an error
Uncaught TypeError: undefined is not a function
in the following line
panelToAddName.getForm().setValues(ob);
There is no such a problem if the store is specified locally inside combobox
store: ['ROLE_ADMIN_USERS']
I guessed there is a problem related to remote list is not loaded when setValue is called, but setting queryMode: 'local', and loading store with list from view controller doesn't fix the issue.
Is there a way to set value to the combobox with remotly loaded list from view controller?
I think the problem is with bind config of your combobox. In Ext5 doc, there is not config with name bind for combobox.
If your store name is role, try writing store:'role' instead of bind.
Hope this will work.
I've finally figured the issue out by setting
queryMode: 'local'
then loading store from the view controller
var storeRole = me.getViewModel().getStore('role');
storeRole.load();
then bindStore of the combo box
var combobox = panelToAddName.items.getAt(0).items.getAt(0).items.getAt(0).items.getAt(2);
combobox.bindStore(storeRole);
If somebody knows how to get combo box in more simplistic way you are welcome to comment. The following does not have a bindStore() method
Ext.ComponentQuery.query('combobox')[0]

ComboBox fires change event on every keypress

I'm trying to build grid with combobox in toolbar, in Grid I will have some informations about employees and combo will allow me to select employee I would like to load those info.
I've created grid easily, but I have problem with combobox in toolbar: it fires change event every time I type something.
Ext.define('My.Grid.Combo', {
extend: 'Ext.form.ComboBox',
fieldLabel: 'Choose State',
store: states,
alias: 'widget.combostates',
queryMode: 'local',
displayField: 'name',
valueField: 'abbr',
forceSelection: true,
listeners: {
change: function (field, newValue, oldValue) {
console.log(newValue);
},
scope: this
}
});
Here is my demo: http://jsfiddle.net/Misiu/LTVXF/
Put cursor inside that combo and start typing. After every key press that event is fired (see console)
I would like to get that event (or other, doesn't matter) to fire after user selects valid element from that checkbox (I'm using forceSelection).
I could add editable: false, but I would like to have local filtering after I enter part of valid value.
The reason this is happening is because it actually is changing the value every time you hit a key. What you want to use is the select listener. Using this you can grab the value out of the record that was selected.
listeners: {
select: function(combo, records, eOpts) {
console.log(records[0].get('name'));
console.log(records[0].get('abbr'));
}
}
Try removing "scope: this". Once you remove it, when you call this in the event you will be able to see the combobox from which the event is fired. Otherwise it will be the value of window.

ExtJS render grid before Store has loaded

I have an editable grid and a store that loads from a proxy. Im using the store.collect() function to load a combobox to the editor of the grid, the thing is that the grid renders itself before the collect() function is finished, so I get an empty combo. How can I make sure the grid renders after the store is loaded? BTW it works fine if I don't use collect().
This is my grid editor combo:
editor: {
xtype: 'combobox',
store: store_ingredientes.collect('ALIMENTO_DESCRIPCION'),
displayField: 'ALIMENTO_DESCRIPCION',
queryMode: 'local',
allowBlank: false
}
If I log the collection on the load event of the store it works as spected:
load: function(){
console.log( store_ingredientes.collect('ALIMENTO_DESCRIPCION'));
}
To wait until the store is loaded you can use:
yourStore.on('load', function(store, records, options){
//this will be executed after store is loaded
});

How to query all ExtJS components which have some config option set

I've specified showCondition custom property for some items inside view config. How can I query all such components?
I've tried Ext.ComponentQuery.query(). The problem is, that query() returns to me correct number of elements, but there are not 'real' components, that is, when I try to do elements[0].hide(), is makes no effect.
I noticed, that when I get the same element using ref in controller class, hide() works perfectly.
After that I've console.log-ed results of both ways of getting the element and noticed strange things. First, returned element have different html id attributes (textfield-1115 and textfield-1089). Second, the element which is returned by query() method already has hidden=true property (that's why hide() has no effect). Both elements are textfield components.
Below are related code parts. The important is in onAfterRenderForm().
In view:
Ext.define('MyApp.view.Test', {
extend: 'Ext.container.Container',
alias: 'widget.test',
layout: 'fit',
initComponent: function() {
Ext.apply(this, {
items: [
{
title: 'form',
itemId: 'myForm',
xtype: 'form',
items: [
{
xtype: 'textfield',
fieldLabel: 'code',
showCondition: 'is-root',
allowBlank: false,
vtype: 'alphanum'
}
]
}
]
});
this.callParent(arguments);
}
});
In controller:
Ext.define('MyApp.controller.Test', {
extend: 'Ext.app.Controller',
requires: [
'MyApp.view.Test'
],
refs: [
{
ref: 'codeField', selector: '[showCondition]'
}
],
init: function() {
this.control(
{
'#myForm': {
afterrender: this.onAfterRenderForm
}
);
},
onAfterRenderForm: function(oForm) {
var elements = oForm.query('[showCondition]');
console.log(elements[0]);
console.log(this.getCodeField());
if(elements[0].id == this.getCodeField().id)
alert('Elements are not the same!!!');
}
});
This:
refs: [{
ref: 'codeField', selector: '[showCondition']
}]
is subtly different from oForm.query('[showCondition]')[0].
For the ref you a grabbing the first component found with a defined showCondition value. In oForm.query, you are grabbing the first component found that is a child of oForm which has a defined showCondition value.
That means that if you have other fields in any view within your app that have showCondition defined on them, the call to the generated getter for the ref could return any one of those fields. It depends on what order Ext decides to put them in.
It sounds to me like a couple things are happening
You have other fields in your app that have showCondition defined but are not on the form your controller is looking at.
Your view is being rendered in the hidden state. Is is being added as an item in a card layout or something like that?

Resources