How to reuse the existing store to populate the combobox in Extjs? - extjs4.1

I have a "Ext.grid.Panel" , which is populated using the store.
Combobox need to be populated with the values from the "Ext.grid.panel" 1st one column.
Ex: Sample UI.
_______
|Button |
-------
-----------------------------
emp name | emp no
-----------------------------
xxx ABC
yyy XYZ
----------------------------
Question :
if the user clicks the above button i need to show popup with form with combobox as form field. it needs to be populated with the "emp name" from the
above grid. i am using the store to populate the grid. how to use the same store for populating the combobox ?

If you create the store outside the initialization of the grid panel, you can use it as many places as you would like - I'm a little out of practice, but something like this in the init function of a view/panel/container (definitely an error or two since this is just off memory from ext a year ago) and you might need to double check this all in the docs:
init: function () {
var store = Ext.create('App.store.Employees').load();
var contextMenu = Ext.create('Ext.menu.Menu', {
items: {xtype: 'form', items: [
{xtype: 'combo', store: store}
]
});
var grid = Ext.create('Ext.grid.Panel', {
store: store,
columns [....]
});
Ext.applyIf(this, {
items: [
{xtype: 'button', itemId: 'MyButton'},
grid
]
});
this.callParent(arguments);
var button = Ext.ComponentQuery.query('#MyButton')[0]
button.getEl().on('contextmenu', function (e) {
e.preventDefault();
contextMenu.show(button.getEl());
});
}

Related

dgrid inside ContentPane - Scroll error

I have a problem with dgrid.... I have an AccordionContainer, and in each ContentPane of it,
I place a dgrid. The problems with the dgrid are:
1- Error with scroll: when scrolling down, in certain moment the scroll "skips" and jumps into the end and there's no way to scroll up and show the first records.
(I have seen in Firebug the error TypeError: grid._rows is null when the scroll fails).
2- Trying to change a value: sounds like no dgrid-datachange event is emitted,
no way to capture the event after editing a value.
I think these errors has to do with having dgrid inside layouts (dgrid inside ContentPane, inside AccordionContainer). I also included the DijitRegistry extension but even with this extensions I can't get
rid of this errors.
I have prepared this fiddle which reproduces the errors:
https://jsfiddle.net/9ax3q9jw/5/
Code:
var grid = new (declare([OnDemandGrid, DijitRegistry,Selection, Selector, Editor]))({
collection: tsStore,
selectionMode: 'none',
columns:
[
{id: 'timestamp', label:'Timestamp', formatter: function (value,rowIndex) {
return value[0];
}},
{id: 'value', label: 'Value',
get: function(value){
return value[1];
},
editor: "dijit/form/TextBox"
}
],
showHeader: true
});
grid.startup();
grid.on('dgrid-datachange',function(event){
alert('Change!');
console.log('Change: ' + JSON.stringify(event));
});
//Add Grid and TextArea to AccordionContainer.
var cp = new ContentPane({
title: tsStore.name,
content: grid
},"accordionContainer");
Any help will be appreciated,
Thanks,
Angel.
There are a couple of issues with this example that may be causing you problems.
Data
The store used in the fiddle is being created with an array of arrays, but stores are intended to work with arrays of objects. This is the root of the scrolling issue you're seeing. One property in each object should uniquely identify that object (the 'id' field). Without entry IDs, the grid can't properly keep track of the entries in your data set. The data array can easily be converted to an object array with each entry having timestamp and value properties, and the store can use timestamp as its ID property (the property it uses to uniquely identify each record).
var records = [];
var data = _globalData[0].data;
var item;
for (var i = 0; i < data.length; i++) {
item = data[i];
records.push({
timestamp: item[0],
value: item[1]
});
}
var tsStore = new declare([Memory, Trackable])({
data: records,
idProperty: 'timestamp',
name: 'Temperature'
});
_t._createTimeSeriesGrids(tsStore);
Setting up the store this way also allows the grid column definitions to be simplified. Using field names instead of IDs will allow the grid to call formatter functions with the corresponding field value for each row object.
columns: [{
field: 'timestamp',
label: 'Timestamp',
formatter: function (value) {
return value;
}
}, {
field: 'value',
label: 'Value',
formatter: function (value) {
return value;
},
editor: "dijit/form/TextBox"
}],
Loading
The fiddle is using declarative widgets and Dojo's automatic parsing functionality to build the page. In this situation the loader callback does not wait for the parser to complete before executing, so the widgets may not have been instantiated when the callback runs.
There are two ways to handle this: dojo/ready or explicit use of the parser.
parseOnLoad: true,
deps: [
...
dojo/ready,
dojo/domReady!
],
callback: function (..., ready) {
ready(function () {
var _t = this;
var _globalData = [];
...
});
}
or
parseOnLoad: false,
deps: [
...
dojo/parser,
dojo/domReady!
],
callback: function (..., parser) {
parser.parse().then(function () {
var _t = this;
var _globalData = [];
...
});
}
Layout
When adding widgets to containers, use Dijit's methods, like addChild and set('content', ...). These typically perform actions other than just adding a widget to the DOM, like starting up child widgets.
var cp = new ContentPane({
title: tsStore.name,
content: grid
});
registry.byId('accordionContainer').addChild(cp);
instead of
var cp = new ContentPane({
title: tsStore.name,
content: grid
}, "accordionContainer");
In the example code a ContentPane isn't even needed since the dgrid inherits from DijitRegistry -- it can be added directly as a child of the AccordionContainer.
This will also call the grid's startup method, so the explicit call in the code isn't needed.
registry.byId('accordionContainer').addChild(grid);
It also often necessary to re-layout the grid's container once the grid has been initially rendered to ensure it's properly sized.
var handle = grid.on('dgrid-refresh-complete', function () {
registry.byId('accordionContainer').resize();
// only need to do this the first time
handle.remove();
});

How to add panel as list item in Sencha touch 2.1?

I am trying to dynamically add list(with its items) to my container.
Instead of simple HTML template, I need list items to contain panel with a title bar, image & few more things.
To do this I am loading store data and within its callback creating List & array of items. Then I add items to the list and list to the container but end result is just last panel visible instead of sliding list of all panels.
Here is my code:
var vLists = [];
this.load({
callback: function(records, operation, success) {
var hccontainer = Ext.getCmp('hccontainer');
this.each(function(record){
var sid = 'styleStore'+record.get('id');
var styleTemplate = eval('tpls.styleTemplate_' + record.get('id'));
vLists.push({
xtype: 'panel',
scrollable: 'false',
layout: 'fit',
cid : record.get('id'),
ctype : record.get('type'),
cname : record.get('name'),
stid : sid,
tp : styleTemplate,
items: [
{
xtype : 'titlebar',
title : record.get('name'),
docked : 'top',
cls : 'x-toolbar-transparent-top'
},
{
xtype : 'image',
src : record.get('image'),
}
]
});
});
//hccontainer.remove(Ext.getCmp('hc'), true);
Ext.getCmp('hc').destroy();
var hc1 = Ext.create('Ext.dataview.List', {
layout : 'fit',
config: {
direction: 'horizontal',
id : 'hc'
}
});
hc1.setItems(vLists);
Ext.getCmp('hccontainer').add(hc1);
},
scope: this
});
Is this right way to add items or I am missing something.
PS Instead of List if I use Carousel, this works fine
Carousel is more of a layout component than List is. It doesn't look like you need to use a list, I don't see any handler for item taps for example. If you want to avoid using templates than you should not use a List. Instead just make a component with a list-like layout. I would use a container with a vbox layout, scretched horizontally and with a static height. You can then put whatever item configuration you want into this.

How to change data in combo based on other data selected in extjs 4

I am using extjs 4.0.7. I have a requirement wherein I have two combo boxes in the edit mode of a grid and I need to change the data in the second based on the value selected in the first one.
I am using MVC architecture for extjs and a java code that returns json string to populate data in the combo boxes. The code for my first combo box is:
view file:
items: [{
id: 'country',
header: 'Countries',
field: {
xtype: 'combo',
store: [
["USA","USA"],
["India","India"],
],
editable: false,
allowBlank: false,
listeners: {
select: function(combo, records, eOpts){
contactTypeGrid = combo.getValue();
myGrid.fireEvent('LoadStateOnSelect');
}
}
}
},
{
id: 'states',
header: 'Sates',
dataIndex: 'states',
field: {
xtype: 'combo',
store: 'StateStore',
valueField: 'stateDesc',
displayField: 'stateText',
}
}, ....
]
controller:
LoadStateOnSelect: function(){
contactTypeGrid = contactTypeGrid.toLowerCase();
var stateStore = this.getStateStoreStore();
stateStore.getProxy().url = "myURL.do";
stateStore.getProxy().extraParams.act = contactTypeGrid;
stateStore.load();
},
However, when I run this code, the data in the second store changes in the background but a Loading mask continues to appear in front due to which I cannot select any value.
How should I resolve the issue of connditional data load? Any help will be much appreciated.
Have you tried clearing the selected value in the combobox before reloading the store? You could try calling the clearValue() method on the combo.
I have a temporary fix for this. However, I am still looking for a solution that is more stable and workable.
Solution:
Whenever changing the data in the dependant store you could expand the combo box which loads the new data correctly.
LoadStateOnSelect: function(){
contactTypeGrid = contactTypeGrid.toLowerCase();
var stateStore = this.getStateStoreStore();
stateStore.getProxy().url = "myURL.do";
stateStore.getProxy().extraParams.act = contactTypeGrid;
statesCombo.expand(); //Here I am assuming that "statesCombo" has a
//reference to the dependant combo box.
stateStore.load();
},
This might save somebody else's time however, In case somebody finds a more viable solution, please let me know as well.
carStore- any store for main combo
carModelStore - store, the content of which should be depended on selection in the carStore
Consider more general and useful example when data is getting from server.
var carModelStore = new Ext.data.Store({
reader: new Ext.data.JsonReader({
fields: ['id', 'car-model'],
root: 'rows'
}),
storeId: 'car-model-store',
proxy: new Ext.data.HttpProxy({
url: 'carmodeldataprovider.json?car-name=lamborghini'
}),
autoLoad: true
});
{ xtype: 'combo', name: 'car-name', fieldLabel: 'Car', mode: 'local', store: carStore, triggerAction: 'all',
listeners: {
select: function(combo, records, eOpts){
var carName = records.get('car-name');
var carModelStore = Ext.StoreMgr.lookup("car-model-store");
carModelStore.proxy.setUrl('carmodeldataprovider.json?car-name=' + carName, false);
carModelStore.reload();
}
}
}

Extjs4 - Reloading store inside itemselector

I have an itemselecor inside a grid, and i have an combobox that should reload only the store inside the itemselector( the value fields should remain intact)
Here is the itemselector
var grid = Ext.widget('form', {
id: 'grid',
title: '',
width: 600,
bodyPadding: 10,
renderTo: 'itemselectorproduto',
items: [{
xtype: 'itemselector',
name: 'itemselector',
id: 'itemsel',
anchor: '100%',
imagePath: '/ux/images/',
store: store,
displayField: 'Nome',
valueField: 'ID',
value: vitrine,
allowBlank: true,
msgTarget: 'side'
}]
});
I tried to call the normal store.load(), but it have no effect and it shows no error on the console
If needed i will post more of the code, but i think just this should be enough
Thanks,
Looking through the code if ItemSelector it doesn't look like it supports any changes in the store once it's been binded. It basically creates local copies of the data. And if you call bindStore method to assign different store - it will erase your selection.
You can always improve code in ItemSelector to allow such behavior. It should not be a problem. You can subscribe to datachanged or load event of the store when binding to it, and then handle situation when store data is changed.
Actually i think the best way to do such thing is using ItemSelector`s "populateFromStore". Sure except of extending item selector. In case of extending you should look on the "onBindStore" function of the ItemSelector.
onBindStore: function(store, initial) {
var me = this;
if (me.fromField) {
me.fromField.store.removeAll()
me.toField.store.removeAll();
// Add everything to the from field as soon as the Store is loaded
if (store.getCount()) {
me.populateFromStore(store);
} else {
me.store.on('load', me.populateFromStore, me);
}
}
}
So as you see in case of the empty store it hooks to the load event. And it should be like this:
onBindStore: function(store, initial) {
var me = this;
if (me.fromField) {
me.fromField.store.removeAll()
me.toField.store.removeAll();
me.store.on('load', me.populateFromStore, me);
// Add everything to the from field as soon as the Store is loaded
if (store.getCount()) {
me.populateFromStore(store);
}
}
}

ST2: Using 2 unique instances of a store & MVC

I have a simple test app where I have a carousel that will instantiate multiple of the same type of grid, each grid having it's own copy of a store.
Carousel:
Ext.define('App.view.TopPageCarousel', {
extend: 'Ext.Carousel',
xtype : 'app-toppagecarousel',
requires: ['Ext.Carousel', 'App.view.TopPageGrid'],
config: {
title: 'Top Pages',
items: [{
xtype : 'app-toppagegrid',
title : 'titleA'
},{
xtype : 'app-toppagegrid',
title : 'titleB'
}]
}
});
At first I was defining the store in the grid as a property in its config and I have the controller listening for store changes, just to let me know it was being loaded. The ajax call is made and the grid was populated. However, All grid's were populated with the same data even though unique data was being returned with each call.
Then I found a post that said I needed to instantiate the stores as the grid is being populated, like so:
constructor : function() {
var me = this;
Ext.apply(me, {
store : me.buildStore()
});
me.callParent(arguments);
me.store.load({params : {ufq : this.title}});
},
buildStore : function() {
return Ext.create('App.store.Links');
}
This sort of works. The ajax call is being made, but the grid isn't being populated now and I am not seeing the console.log("Store loaded"); being executed that I placed in the controller. What am I doing wrong?
It turns out in ST2 instead of using Ext.create, the best thing to do is (in my particular instance, not as a standard):
constructor : function() {
this.callParent(arguments);
Ext.setStore('App.store.Links');
},
Using Ext.getStore & Ext.setStore are necessary now if you want a lot of the benefits that go along with events & the store manager.