Creating checkboxgroup from extjs store - extjs

I want to create checkbox group from store populated from an array.
Here is my store.
var checklistStore = new Ext.data.Store({
data: arraySubT,
fields: ['id', 'boxLabel']
});
and currently my checkbox group in only getting displayed from an array and not store.
xtype: 'checkboxgroup',
fieldLabel: 'Checklist',
columns: 1,
vertical: true,
listeners: {
change: function(field, newValue, oldValue, eOpts){
}
},
items: checkboxconfigs
However I want to make it displayed from store.How can I achieve this?

[EDIT]
For your and my convenience, I made a general component which you can use. It may need some tuning regarding the store events that it reacts to. Find it in this fiddle.
[/EDIT]
You have to do it manually:
renderCheckboxes:function() {
checkboxgroup.removeAll();
checkboxgroup.add(
checklistStore.getRange().map(function(storeItem) {
return {
// map the storeItem to a valid checkbox config
}
})
);
}
and repeat that over and over and over again when the store data changes. That is, you have to attach to the store events:
checklistStore.on({
load:renderCheckboxes,
update:renderCheckboxes,
datachanged:renderCheckboxes,
filterchange:renderCheckboxes,
...
})
Maybe you will overlook some events you have to attach to, but sooner or later you will have all edge cases covered.

Here is working fiddle for you.
Just loop through store data with Ext.data.Store.each() method and setup your checkbox group items.
var _checboxGroupUpdated = function() {
// Use whatever selector you want
var myCheckboxGroup = Ext.ComponentQuery.query('panel checkboxgroup')[0];
myCheckboxGroup.removeAll();
myStore.each(function(record) {
myCheckboxGroup.add({
boxLabel: record.get('fieldLabel'),
inputValue: record.get('value'),
name: 'myGroup'
});
});
}
// Add all listeners you need here
myStore.on({
load: _checboxGroupUpdated,
update: _checboxGroupUpdated,
datachanged: _checboxGroupUpdated
// etc
});

Related

Extjs widget tagfield can't set selected value in list from remote store

I have a trouble with my tagfield inside widgetcolumn.
I used remote store for tagfield and "autoLoadOnValue" for display loaded value in column. And it's works right. But i have a problem with values list.
If a column has a value, it is not highlighted as selected in the list. But in html the loaded value is defined as the selected.
And if you select a different value, two values will be highlighted at once.
How can I make it so that when I expand the list, the value loaded in the column is highlighted? Is there any way to update the drop-down list?
This my fiddle: https://fiddle.sencha.com/#view/editor&fiddle/3d29
UPD: queryMode: 'local' does not work for me because in my app I load the store with extraParams and I always get new values for store
Any ideas??
It happens because your tag field store is reloading on expand and loosing the selected values. You can use queryModel: 'local' to prevent store reload.
...
widget: {
xtype: 'tagfield',
store: this.tagStore,
valueField: 'tag',
displayField: 'field',
autoLoadOnValue: true,
//filterPickList: false,
queryMode : 'local', // use this to avoid store reload on
listeners: {
select: function (cmp, record) {
const dataIndex = cmp.getWidgetColumn().dataIndex;
const widgetRecord = cmp.getWidgetRecord()
let valuesArr = [];
Ext.each(record, function (item) {
valuesArr.push(item.data.tag)
})
widgetRecord.set(dataIndex, valuesArr);
console.log(record)
}
}
}
...
Or you can use the following override (or you can extend the tag field with appropriate logic) to store the selected value and after store reload re-select it:
Ext.define('overrides.form.field.Tag', {
override: 'Ext.form.field.Tag',
initComponent: function() {
this.getStore().on('beforeload', this.beforeStoreLoad, this);
this.getStore().on('load', this.afterStoreLoad, this);
this.callParent();
},
beforeStoreLoad: function(store) {
this.beforeStoreLoadFieldValue = this.getValue();
},
afterStoreLoad: function(store) {
this.setValue(this.beforeStoreLoadFieldValue);
}
});

ExtJS - After clearing filter(s) of store, type query does not work

I'm using instances of a combobox for multiple user interfaces. So I need to reset combobox stores when user focuses on it. Combo's store is locally sorted; so I execute clearFilter() function of Ext.data.Store class - it works as it is expected except that typing query does not work anymore.
Here is my combobox configuration:
forceSelection: true,
autoSelect: false,
typeAhead: false,
triggerAction: 'all'
Store configuration:
autoLoad: false,
autoSync: false,
remoteSort: false,
proxy: {
type: 'ajax'
// other configs
}
Edit: fiddle
Note: Store of combobox used in fiddle is populated with static data when the original one uses an AJAX proxy
I think i solved your problem by looking at this post:
ExtJs: Search / Filter within a ComboBox
Adding a custom filter on each keystroke on the combobox seems to resolve your issue:
enableKeyEvents:true,
listeners: {
'keyup': function() {
this.getStore().clearFilter();
this.getStore().filter('name', this.getRawValue(), true, false);
},
'beforequery': function(queryEvent) {
queryEvent.combo.onLoad();
}
}
It is not beautiful, but i think it works. Take a look at this extended fiddle:
https://fiddle.sencha.com/#fiddle/teg
As I understand from your fiddle, you have trouble that implementing filter to different comboboxes. I think the problem you currently use same store for comboboxes. That's why you should also change the store for each combobox. Add this code to your fiddle.
combo1.getStore().filter('nationality', 'USA');
container.on('tabchange', function(tabpanel, newCard, oldCard, eOpts) {
combo2.getStore().clearFilter();
combo1.getStore().filter('nationality', 'USA');
if (combo2.getValue()) {
combo1.getStore().clearFilter();
combo1.getStore().filter('userId', combo2.getValue())
}
});
Btw, I put the filter before tabchange event because of static store. But, you might want to add the filter store listener if you use proxy(AJAX) store. Like this:
listeners: {
load: function(store, records) {
store.filter('nationality', 'USA');
}
}
Edit:
var store = combo1.getStore();
store.filter('nationality', 'USA');
container.on('tabchange', function(tabpanel, newCard, oldCard, eOpts) {
if (newCard.title == 'Panel 1') {
store.clearFilter();
store.filter('nationality', 'USA');
} else if (newCard.title == 'Panel 2') {
store.clearFilter();
// Or whatever filter because you have to change the store
// dynamically if you wanna use same store for different combos
}
});
Hope this helps. Good luck.

Populating the value of a Label

I am using the MVC architecture (i have gone through the docs on MVC, but i am still lost here) and i need to know how to populate the records on to my Label. I know that i have to get this done by Stores.
I have loaded the values from the store, but unable to display it on my Panel for some reason. here's my code;
Most of the examples/books demonstrates how to display in a grid, but not a label (I know it has to be the same logic, but i am lost). And it shows how to write to a DB/JSON file and not display the values.
I need to display the COUNTRYNAME in the Label text. This is an example code that i am doing to understand this, can some one help me ?
Ext.define ('ProjectDisplayExample.model.Country',{
extend: 'Ext.data.Model',
//
fields:['countryid','countryname']
//
});
STORE
Ext.define('ProjectDisplayExample.store.Country',{
extend:'Ext.data.Store',
model:'ProjectDisplayExample.model.Country',
remoteGroup:true,
proxy: {
actionMethods : {
read : 'POST',
},
type: 'ajax',
url : '/server/country.php'
}
});
VIEW
Ext.define('ProjectDisplayExample.view.CountryWindow', {
extend: 'Ext.window.Window',
alias: 'widget.countrywindow',
...........
initComponent: function() {
var st = Ext.getStore('Country');
st.load();
this.items = [
{
items: [
{
xtype: 'panel',
region: 'north',
items: [{
xtype: 'label',
// NEED TO DISPLAY COUNTRT NAME FROM THE STORE HERE
}]
}]
}
UPDATE
var store = ... // Your store
store.on('load', function() {
// here store is loaded and you can do anything you want with it
console.log('store is loaded. number of records = ', store.getCount());
}, this, { single: true });
store.load; // I ADDED THIS LINE.................... <---------
UPDATE 2
this.items = [
{
items: [
{
xtype: 'panel',
region: 'north',
items: [{
xtype: 'label',
name : f
}]
}]
I will not post a code sample to exactly solve your question, but I will give you couple points:
Store contains array or records. So you can't just say give me country name from the store. You need first to get a record, for example: var r = store.getAt(0), and only after that you can get countyname field var f = r.get('countryname').
Load() method is asynchronous, so you can just execute it somewhere in the code and assume that for the very next line your store is ready. You need to subscribe to the load event, something like:
var store = ... // Your store
store.on('load', function() {
// here store is loaded and you can do anything you want with it
console.log('store is loaded. number of records = ', store.getCount());
}, this, { single: true });
store.load();
Labels as in xtype: label are actually very rarely used in ExtJs. What exactly are you trying to display in that panel? But anyhow... after you get data out of the store you can use something like update() or setValue() or any other method to update component.
Hope this helps...

How do I set a Ext Grid Filter Default?

I have a working sort-able grid using the ext 3.4 grid filter plugin. I would like to default the active column to filter true values. User who needs the inactive records could remove the filter. How do I specify a default filter column and value?
Thanks in advance!
colModel: new Ext.grid.ColumnModel({
defaults: {
sortable: true
// How do I specify a default filter value
//
// Only show active records unless the user changes the filter...
},
columns: [{
dataIndex:'f_uid',
id:'f_uid',
header:'ID',
hidden:true
}, {
dataIndex:'f_name',
id:'f_name',
header:'Name',
}, {
xtype:'booleancolumn',
dataIndex:'f_active',
id:'f_active',
header:'Active',
filterable:true,
trueText:'Active',
falseText:'Inactive'
}]
I realise this is an old question but it took me a while to find a solution, therefore I thought I would share.
1) The filter can be set using the value property in the filter.
filter: {
type: 'LIST',
value: ['VALUE TO FILTER']
}
2) In order to initially filter the data use the filterBy() method in the store. This could be defined in the onRender event handler.
this.getStore().load({
scope:this,
callback: function() {
// filter the store
this.getStore().filterBy(function(record, id) {
// true will display the record, false will not
return record.data.DATA_TO_FILTER == 'VALUE TO FILTER ';
});
}
});
The answer was in the Filter.js source code. The filter object within the column definition can be used to configure the default behavior.
}, {
xtype:'booleancolumn',
dataIndex:'f_active',
id:'f_active',
header:'Active',
trueText:'Active',
falseText:'Inactive',
filterable:true,
filter: {
value:1, // 0 is false, 1 is true
active:true // turn on the filter
}
}
I have encountered the same problem and I found that #John's answer is right, I can make it work with the sample http://dev.sencha.com/deploy/ext-4.0.0/examples/grid-filtering/grid-filter-local.html, for the grid-filter-local.js, just add the code like:
grid.getStore().load({
scope:this,
callback: function() {
// filter the store
grid.getStore().filterBy(function(record, id) {
// true will display the record, false will not
return record.data.size === 'small';
});
}
});
before the original code store.load(), and wipe off the store.load().
Then it will only show the record with size equals 'small' at the first load of the web page. Cheers!
I've made a universal helper class that allows you to set any default values in column definition.
https://gist.github.com/Eccenux/ea7332159d5c54823ad7
This should work with both remote and static stores. Note that this also works with filterbar plugin.
So your column item is something like:
{
header: 'Filename',
dataIndex: 'fileName',
filter: {
type: 'string',
// filename that starts with current year
value: Ext.Date.format(new Date(), 'Y'),
active:true
}
},
And then in your window component you just add something like:
initComponent: function() {
this.callParent();
// apply default filters from grid to store
var grid = this.down('grid');
var defaultFilters = Ext.create('Ext.ux.grid.DefaultFilters');
defaultFilters.apply(grid);
},

Using PagingToolbar and CheckboxSelectionModel in single GridPanel

I've posted this over on the Sencha forums, wanted to also post it here just in case:
I have a GridPanel that utilizes a PagingToolbar and a CheckboxSelectionModel. I want to keep track of selections across pages. I'm nearly there, but I'm running into issues with the PagingToolbar controls (such as next page) firing a 'selectionchange' event on the my selection model.
Here's a simplified sample of my code:
Code:
var sm = Ext.create('Ext.selection.CheckboxModel', {
listeners:{
selectionchange: function(selectionModel, selectedRecords, options){
console.log("Selection Change!!");
// CODE HERE TO KEEP TRACK OF SELECTIONS/DESELECTIONS
}
}
});
var grid = Ext.create('Ext.grid.Panel', {
autoScroll:true,
store: store,
defaults: {
sortable:true
},
selModel: sm,
dockedItems: [{
xtype: 'pagingtoolbar',
store: store,
dock: 'bottom',
displayInfo: true
}],
listeners: {'beforerender' : {fn:function(){
store.load({params:params});
}}}
});
store.on('load', function() {
console.log('loading');
console.log(params);
console.log('selecting...');
var records = this.getNewRecords();
var recordsToSelect = getRecordsToSelect(records);
sm.select(recordsToSelect, true, true);
});
I assumed that I could select the records on the load event and not trigger any events.
What's happening here is that the selectionchange event is being triggered on changing the page of data and I don't want that to occur. Ideally, only user clicking would be tracked as 'selectionchange' events, not any other component's events bubbling up and triggering the event on my selection model. Looking at the source code, the only event I could see that fires on the PagingToolbar is 'change'. I was trying to follow how that is handled by the GridPanel, TablePanel, Gridview, etc, but I'm just not seeing the path of the event. Even then, I'm not sure how to suppress events from the PagingToolbar to the SelectionModel.
Thanks in advance,
Tom
I've managed to handle that. The key is to detect where page changes. Easiest solution is to set buffer for selection listener and check for Store.loading property.
Here is my implementation of selection model:
var selModel = Ext.create('Ext.selection.CheckboxModel', {
multipageSelection: {},
listeners:{
selectionchange: function(selectionModel, selectedRecords, options){
// do not change selection on page change
if (selectedRecords.length == 0 && this.store.loading == true && this.store.currentPage != this.page) {
return;
}
// remove selection on refresh
if (this.store.loading == true) {
this.multipageSelection = {};
return;
}
// remove old selection from this page
this.store.data.each(function(i) {
delete this.multipageSelection[i.id];
}, this);
// select records
Ext.each(selectedRecords, function(i) {
this.multipageSelection[i.id] = true;
}, this);
},
buffer: 5
},
restoreSelection: function() {
this.store.data.each(function(i) {
if (this.multipageSelection[i.id] == true) {
this.select(i, true, true);
}
}, this);
this.page = this.store.currentPage;
}
And additional binding to store is required:
store.on('load', grid.getSelectionModel().restoreSelection, grid.getSelectionModel());
Working sample: http://jsfiddle.net/pqVmb/
Lolo's solution is great but it seems that it doesn't work anymore with ExtJS 4.2.1.
Instead of 'selectionchange' use this:
deselect: function( selectionModel, record, index, eOpts ) {
delete this.multipageSelection[i.id];
},
select: function( selectionModel, record, index, eOpts ) {
this.multipageSelection[i.id] = true;
},
This is a solution for ExtJs5, utilizing MVVC create a local store named 'selectedObjects' in the View Model with the same model as the paged grid.
Add select and deselect listeners on the checkboxmodel. In these functions add or remove the selected or deselected record from this local store.
onCheckboxModelSelect: function(rowmodel, record, index, eOpts) {
// Add selected record to the view model store
this.getViewModel().getStore('selectedObjects').add(record);
},
onCheckboxModelDeselect: function(rowmodel, record, index, eOpts) {
// Remove selected record from the view model store
this.getViewModel().getStore('selectedObjects').remove(record);
},
On the pagingtoolbar, add a change listener to reselect previously seleted records when appear in the page.
onPagingtoolbarChange: function(pagingtoolbar, pageData, eOpts) {
// Select any records on the page that have been previously selected
var checkboxSelectionModel = this.lookupReference('grid').getSelectionModel(),
selectedObjects = this.getViewModel().getStore('selectedObjects').getRange();
// true, true params. keepselections if any and suppresses select event. Don't want infinite loop listeners.
checkboxSelectionModel.select(selectedObjects, true, true);
},
After whatever action is complete where these selections are no longer needed. Call deselectAll on the checkboxmodel and removeAll from the local store if it will not be a destroyed view. (Windows being closed, they default set to call destroy and will take care of local store data cleanup, if that is your case)

Resources