show dynamic data using checkbox in extjs - extjs

I have a combo box in which the user selects a value, that value is passed to the checkbox data store and it is populated dynamically from database (oracle). I tried the code below. It seems that the selected parameter is being passed to checkbox and I can see the data being populated on the console. I just can't render the checkbox on form. The error I get is: typeError: this.items[0] is undefined.
testArray = new Array();
var testStore = new Ext.data.JsonStore({
proxy:new Ext.data.HttpProxy({
method:'GET',
prettyUrls:false,
url:'kiu.htm',
listeners:{
'loadexception':{
fn:test.form.data.loadException
}
}
}),
fields:["id", "display"],
reader:new Ext.data.JsonReader({
id:'id',
root:'results',
totalProperty:'totalCount',
fields:new Ext.data.Record.create([
{name:'id',type:'int'},
{name:'display',type:'string'}
])
}),
listeners:{
load: function(t, records, options, success) {
for(var i=0; i<records.length; i++) {
testArray.push({name:records[i].data.id, boxLabel: records[i].data.display});
alert(testArray[i].id);
}
}
}
});
{
xtype:'combo',
id:'comboid3',
store:combostore,
displayField:'display',
valueField:'id',
tabIndex:1,
loadingText:'Loading combo...',
listeners :{
select:function(event){
testStore.baseParams = {
"comboid":Ext.getCmp('comboid3').getValue()
};
testStore.load();
}
}
},
{
xtype:'checkboxgroup',
fieldLabel:'Check',
items:testArray
}
Help will be appreciated!

Specifying the Ext JS version is always going to be helpful. It appears this must be 2.x or 3.x and not the current version.
The issue is timing, load calls are asynchronous so by attempting to utilize testArray in this fashion you are likely referencing an empty array by the time it parses the items property of your checkboxgroup. You have a couple options around this... one is to grab a reference to the checkbox group and add the items into it, the other is to not put the checkbox group in the form at all until the call returns and then add it with the populated items array. In either case it is likely that you will need to look up a component reference to either the FormPanel or the CheckboxGroup from within the load handler function and call the 'add' method to add child items.

Related

How to prevent Kendo MultiSelect from losing values after editing in a grid template?

I have a grid that displays a comma-separated list of values, and it has an array that gets used in a template editor for the grid. (On the server, I transform the comma-separated list to an array for the Kendo multiselect AngularJS directive). I have almost everything working: display, edit, and adding values in the multiselect.
There's just one weird thing happening: after I add a value in the multiselect, click Save in the editor, and reopen the editor, the multiselect then only displays one of the most-recently entered values. I know that the values are there and going through the pipeline, because the values make it into the database. I can refresh the page, open the editor, and all the values display in the multiselect correctly, including the one I just added.
It's as if kendo "forgets" most of the values when I reopen the editor. How can this be prevented? Does the MultiSelect need to be rebound to the values? If so, how?
I have tried adding this onChange event, but it had no effect. I've added valuePrimitive to no effect. I tried specifying k-rebind, but it caused an error.
Here's the directive being used in the text/x-kendo-template:
<select kendo-multi-select
id="zipCode"
k-placeholder="'Enter zip codes...'"
style="width: 225px"
k-on-change="dataItem.dirty=true"
k-auto-bind="false"
k-min-length="3"
k-enforce-min-length="true"
k-data-source="options.zipCodeDataSource"
k-data-text-field="'text'"
k-filter="'startsWith'"
k-filtering="options.zipCodeFiltering"
k-no-data-template="'...'"
k-ng-model="dataItem.zipArray"
k-highlight-first="true" />
And this is the DataSource:
options.zipCodeDataSource = new kendo.data.DataSource({
severFiltering: true,
transport: {
read: {
url: serviceUrl + "ZipCode/Get",
type: "GET",
dataType: "json",
contentType: jsonType,
data: function (e) {
// get your widget.
let widget = $('#zipCode').data('kendoMultiSelect');
// get the text input
let filter = widget.input.val();
// what you return here will be in the query string
return {
filter: filter
};
}
},
},
schema: {
data: "data",
total: "Count",
model:
{
id: "text",
fields: {
text: { editable: false, defaultValue: 0 },
}
},
parse: function (response) {
return response;
}
},
error: function (e) {
}
});
If I display {{dataItem.zipArray}} in a <pre> all of the expected values are there.
I wonder if something needs to be added to the edit event handler in the kendo grid definition, but I'm not sure what it would be. I've had to do binding like that for the dropdownlist directive.
edit: function (e) {
if (e.model.marketId === 0) {
e.container.kendoWindow("title", "Add");
} else {
e.container.kendoWindow("title", "Edit");
}
// re-bind multi-select here??
// These two lines actually cause the multiselect to lose pre-existing items in dataItem.zipArray
// var multiselect = kendo.widgetInstance(angular.element('#zipCode'));
// multiselect.trigger('change');
}
...
Update:
This dojo demonstrates the issue.
Run the dojo
Edit the first record in the Contracts grid
Add a zip code such as 22250
Click Save
Then click Edit on the first row again
Only zip code 22250 is displayed in the editor
Also, I notice that if I change k-min-length="3" to k-min-length="1", then the issue goes away. But in the scenario I'm working on, it needs to be 3.
This seems to be an issue with kendo itself. Back then this issue was reported here.
Ok based on the reply from telerik, this issue has been fixed in 2017 R3 SP1 release (2017.3.1018). You can verify it by using this updated dojo example:
http://dojo.telerik.com/IREVAXar/3

State provider does not restore sorters properly

I'm trying to store my grid state using the Ext.state.CookieProvider. The problem is I can't restore sorters parameters while state itself (width, order) is restoring properly.
First I've created cookieprovider in init() method of the viewport viewcontroller:
Ext.state.Manager.setProvider(Ext.create('Ext.state.CookieProvider', {}));
My store is set to auto load with remote sorting:
Ext.define('MyApp.requests.store.QueryRequestsGridStore', {
extend: 'Ext.data.Store',
model: 'MyApp.requests.model.QueryRequestsGridModel',
alias: 'store.queryRequestsGrid',
remoteSort: true,
autoLoad: true,
proxy: {
startParam: 'offset',
limitParam: 'limit',
url: '/requests',
noCache: false,
type: 'ajax',
reader: {
type: 'json',
rootProperty: 'data',
totalProperty: 'total'
}
},
});
Store is defined in grid using viewmodel binds:
bind: {
store: '{queryRequestsGrid}'
},
I'm loading the grid containing store from the viewport viewcontroller on button click like this:
var panelToAddName = Ext.create('MyApp.requests.view.QueryRequestsGridView', {});
var mainViewPort = Ext.ComponentQuery.query('#mainViewPort')[0];
var regionPanel = mainViewPort.down('[region=center][xtype=panel]');
regionPanel.removeAll();
regionPanel.add(panel);
Cookie contains sorters, but grid is loaded without any sort parameters.
"storeState":{"sorters":[{"root":"data","property":"date_completed","direction":"ASC"}]}}}
I've dug into the ext-all-debug.js source file and found initState() method of a 'Ext.state.Stateful' class.
initState: function() {
var me = this,
id = me.stateful && me.getStateId(),
hasListeners = me.hasListeners,
state, combinedState, i, len, plugins, plugin, pluginType;
if (id) {
combinedState = Ext.state.Manager.get(id);
if (combinedState) {
state = Ext.apply({}, combinedState);
if (!hasListeners.beforestaterestore || me.fireEvent('beforestaterestore', me, combinedState) !== false) {
plugins = me.getPlugins() || [];
for (i = 0 , len = plugins.length; i < len; i++) {
plugin = plugins[i];
if (plugin) {
pluginType = plugin.ptype;
if (plugin.applyState) {
plugin.applyState(state[pluginType], combinedState);
}
delete state[pluginType];
}
}
me.applyState(state);
if (hasListeners.staterestore) {
me.fireEvent('staterestore', me, combinedState);
}
}
}
}
},
If to log me.store from inside of this method, the store is shown in console as ext-empty-store while me is my loaded grid. Seems like state is applying before the store is properly loaded.
If to reuse the initState method inside beforerender grid event, sorters are restoring from cookie properly.
Any suggestions?
I have not worked with viewmodel binds as the sole bind between store and grid, and can't comment on whether that is supposed to work at all, or just by accident.
But I know that the viewmodel is processed very late, because the view has to be fully initialized first (including applyState), so the viewmodel can find all the components it wants to bind the listeners to.
So please try to add the store using any of the two "old-school" methods that work even without the viewmodel: store:'MyStoreId' or store:Ext.create('MyApp.store.MyStore') on the grid. That way, the store should be bound to the grid before applyState.
Furthermore, I see another issue you should address: Your store loads directly after store init. (autoLoad:true). At that time, it is not yet bound to the grid; thus, no sort/filter has been applied, which means that with remoteSort/remoteFilter enabled, you are sending too many requests to the server. I would recommend to load the store only after it has been applied to the grid (in grid.initComponent after the callParent call, or from grid.boxready listener). If you really want to use autoLoad, I'd recommend to look into setAutoLoad method

Extjs : Selecting same value in multiselect combo not removing value

I am using ext5 multiselect combo. If we select a value from the dropdown, say 'Other' and click outside to cancel the dropdown.
Now the value 'Other' will be shown in combo.
Again click the dropdown and select tha same value 'Other', it should remove 'Other' from its values. But rather it adds same value once again.
My code is given below:
xtype: 'combo',
emptyText: 'Retail BI',
name: 'chainRefId',
store: Ext.create('shared.store.filter.ChainRefs'),
displayField: 'name',
multiSelect: true,
valueField: 'chain_ref_id',
listeners: {
expand: function(){
this.getStore().load();
},
change: function(combo, newVal) {
if (!combo.eventsSuspended) {
var storeCombo = Ext.ComponentQuery.query('combo[name=storeId]')[0];
storeCombo.getStore().removeAll();
storeCombo.setValue(null);
var chainCombo = Ext.ComponentQuery.query('combo[name=chainId]')[0];
chainCombo.getStore().removeAll();
chainCombo.setValue(null);
}
}
}
Is there a solution for this?
Thanks in advance.
Your combo's store gets reloaded on each expand. Technically the record corresponding to the value you selected the first time disappears on the second store load, so the removing logic does not "see" it and therefore leaves it in the field.
Remove this:
expand: function(){
this.getStore().load();
}
and just use autoLoad: true on the store.
I have faced the same problem. I have provided a workaround for this. This fix holds good for tagfield too.
//on combo store load event
load: function () {
// I am assuming reference to combo
var rawVal = combo.getValue();
// If combo is multiselct, getValue returns an array of selected items.
// When combo is configured as remote, everytime it loads with new records and therefore removes the old reference.
// Hence, do setValue to set the value again based on old reference.
combo.setValue(rawVal);
// Here you can see, based on old reference of selected items, the drop down will be highlighted.
}

ExtJs combo loses selected value on store page load

I have an ExtJS 4.1 combo box with a JsonStore and queryMode: 'remote', with paging and filtering, as such:
...
queryMode: 'remote',
allowBlank: true,
forceSelection: true,
autoSelect: false,
pageSize: 25,
typeAhead: true,
minChars: 2,
...
When I load my form with a saved value in this combo box, I load the store passing the saved value as a query (filtering) parameter, to make sure that the selected value is definitely within the returned records, and then I set that value as the combo selected value as such:
mycombo.getStore().load({
params: {
query: displayField
},
scope: {
field: combo,
valueField: valueField,
displayField: displayField
},
callback: function(records, operation, success) {
this.field.setValue(this.valueField);
}
});
So far, so good, the above works fine. The problem is, that if the user then clicks on the dropdown arrow to select another value for the combo, the 1st page of the store is loaded, erasing all previously selected values, and even if nothing is selected, the previously selected value is lost.
This problem is generic, and is quite similar to this question:
ExtJS paged combo with remote JSON store. Display selected value with paging
and can be summarized as such:
In an ExtJS combo box with a remote store and paging, selected values are lost when the loaded page changes.
I tried setting clearOnPageLoad: false for the store, but then each time a new page is loaded, the records are appended to the end of the list. I would have expected this parameter to cache the loaded pages and still show me the correct page while moving back and forth.
So, any ideas on how to keep the selected value while moving between pages? I suppose I could create a record with the selected value manually and append it to the store on each page load until a new value is selected, but this sounds like too much effort for something so basic.
We ended up contacting Sencha support since we have a paid license. This is the answer we got back:
Ext.override(Ext.form.field.ComboBox, {
onLoad: function() {
var me = this,
value = me.value;
if (me.ignoreSelection > 0) {
--me.ignoreSelection;
}
if (me.rawQuery) {
me.rawQuery = false;
me.syncSelection();
if (me.picker && !me.picker.getSelectionModel().hasSelection()) {
me.doAutoSelect();
}
}
else {
if (me.value || me.value === 0) {
if (me.pageSize === 0) { // added for paging; do not execute on page change
me.setValue(me.value);
}
} else {
if (me.store.getCount()) {
me.doAutoSelect();
} else {
me.setValue(me.value);
}
}
}
}
});
Had the same problem, and 'pruneRemoved: false' didn't work (it seems to be used only in grids). This is the solution:
Ext.override(Ext.form.field.ComboBox,{
// lastSelection is searched for records
// (together with store's records which are searched in the parent call)
findRecord: function(field, value) {
var foundRec = null;
Ext.each(this.lastSelection, function(rec) {
if (rec.get(field) === value) {
foundRec = rec;
return false; // stop 'each' loop
}
});
if (foundRec) {
return foundRec;
} else {
return this.callParent(arguments);
}
}
});
Hope it doesn't have negative side effects. I've tested it a bit and it seems OK.
I am experiencing this issue in extjs 6.0.1.
I discovered a work around that might be helpful for others.
I used override for onLoad to add the selected record from the combo to the store prior to calling the base onLoad.
This works because if the selected record is in the page being viewed, the combo is smart enough to not clear the selection. In other words, the reason the selection is being cleared as you page is because the selected record is not in the page you are viewing.
onLoad: function (store, records, success)
{
var selection = this.getSelection();
if (selection)
{
records.unshift(selection);
store.insert(0, records);
}
this.callParent(arguments);
}

Extjs Dynamic Grid

I'm trying to create a dynamic grid using ExtJS. The grid is built and displayed when a click event is fired then an ajax request is sent to the server to fetch the columns, records and records definition a.k.a store fields.
Each node could have different grid structure and that depends on the level of the node in the tree.
The only way I came up with so far is :
function showGrid(response, request) {
var jsonData = Ext.util.JSON.decode(response.responseText);
var grid = Ext.getCmp('contentGrid' + request.params.owner);
if (grid) {
grid.destroy();
}
var store = new Ext.data.ArrayStore({
id: 'arrayStore',
fields: jsonData.recordFields,
autoDestroy: true
});
grid = new Ext.grid.GridPanel({
defaults: {
sortable: true
},
id: 'contentGrid' + request.params.owner,
store: store,
columns: jsonData.columns,
//width:540,
//height:200,
loadMask: true
});
store.loadData(jsonData.records);
if (Ext.getCmp('tab-' + request.params.owner)) {
Ext.getCmp('tab-' + request.params.owner).show();
} else {
grid.render('grid-div');
Ext.getCmp('card-tabs-panel').add({
id: 'tab-' + request.params.owner,
title: request.params.text,
iconCls: 'silk-tab',
html: Ext.getDom('grid-div').innerHTML,
closable: true
}).show();
}
}
The function above is called when a click event is fired
'click': function(node) {
Ext.Ajax.request({
url: 'showCtn',
success: function(response, request) {
alert('Success');
showGrid(response, request);
},
failure: function(results, request) {
alert('Error');
},
params: Ext.urlDecode(node.attributes.options);
}
});
}
The problem I'm getting with this code is that a new grid is displayed each time the showGrid function is called. The end user sees the old grids and the new one. To mitigate this problem, I tried destroying the grid and also removing the grid element on each request, and that seems to solve the problem only that records never get displayed this time.
if (grid) {
grid.destroy(true);
}
The behaviour I'm looking for is to display the result of a grid within a tab and if that tab exists replaced the old grid.
Any help is appreciated.
When you are trying to add your grid to the tab like this:
html:Ext.getDom('grid-div').innerHTML,
Ext is not aware of it being a valid grid component. Instead, you are simply adding HTML markup that just happens to look like a grid, but the TabPanel will not be aware that it is a grid component.
Instead you should add the grid itself as the tab (a GridPanel is a Panel and does not need to be nested into a parent panel). You can do so and also apply the needed tab configs like this:
Ext.getCmp('card-tabs-panel').add({
Ext.apply(grid, {
id: 'tab-' + request.params.owner,
title: request.params.text,
iconCls: 'silk-tab',
closable: true
});
}).show();
BTW, constantly creating and destroying grids is not an ideal strategy if you can avoid it. It might be better to simply hide and re-show grids (and reload their data) based on which type of grid is needed if that's possible (assuming the set of grid types is finite).
A potential option is to use the metaData field on the JsonStore that allows dynamic reconfiguring of the grid columns as per new datasets.
From
One of the most helpful blog posts about this that Ive found is this one:
http://blog.nextlogic.net/2009/04/dynamic-columns-in-ext-js-grid.html and the original info is well documented at http://docs.sencha.com/ext-js/3-4/#!/api/Ext.data.JsonReader

Resources