Using Ext.form.Basic.loadRecord to load data into Combo Box Fields with Remote Stores - extjs4

I have a form that has multiple Combo Box fields that are attached to remote stores:
Ext.define('app.ux.form.MyCombo', {
extend: 'Ext.form.field.ComboBox',
alias: 'widget.mycombo',
store: this.store,
displayField: 'displayField',
valueField: 'valueField',
forceSelection: true,
autoSelect: true,
initComponent: function() {
this.addEvents('selectitem');
this.enableBubble('selectitem');
this.callParent(arguments);
this.listeners = {
change: function(field, value) {
this.fireEvent('selectitem', field, value);
}
}
}
})
fieldLabel: 'DisabilityType',
name: 'f_disability_type',
xtype: 'combo',
valueField: 'valueField',
displayField: 'displayField',
forceSelection: true,
autoSelect: true,
store: 'DisabilityTypes'
DisabilityTypes is a basic Ext.data.store with autoLoad set to false and autoSync set to true. When you click on the dropdown tied to the store, the store loads and shows the list of values.
When I call loadRecord on the BasicForm Object that contains this dropdown and pass it a model, it fills in the combo boxes that use local stores, but doesn't load the combo boxes that use remote stores. This is because either the combo box store isn't loaded (autoLoad: false) or the combo box is loaded AFTER the form loads (autoLoad:true).
I am aware that this was a problem in Ext 3.3.x and that there was a plugin made to fix it:
/**
* When combo box is used on a form with dynamic store (remote mode)
* then sometimes the combobox store would load after the form data.
* And in that case the setValue method of combobox will not
* set the combobox value properly. This override makes sure that the
* combobox store is completely loaded before calling the setValue method.
*/
Ext.override(Ext.form.ComboBox, {
setValue : function(v){
var text = v;
if(this.valueField){
if(!Ext.isDefined(this.store.totalLength)){
this.store.on('load', this.setValue.createDelegate(this, arguments), null, {single: true});
if(this.store.lastOptions === null){
var params;
if(this.valueParam){
params = {};
params[this.valueParam] = v;
}else{
var q = this.allQuery;
this.lastQuery = q;
this.store.setBaseParam(this.queryParam, q);
params = this.getParams(q);
}
this.store.load({params: params});
}
return;
}
var r = this.findRecord(this.valueField, v);
if(r){
text = r.data[this.displayField];
}else if(this.valueNotFoundText !== undefined){
text = this.valueNotFoundText;
}
}
this.lastSelectionText = text;
if(this.hiddenField){
this.hiddenField.value = v;
}
Ext.form.ComboBox.superclass.setValue.call(this, text);
this.value = v;
}
});
Has this problem been fixed in Ext 4? Or do I need to find another plugin that's Ext 4 compatible?

My solution:
Ext.form.field.ComboBox.override( {
setValue: function(v) {
v = (v && v.toString) ? v.toString() : v;
if(!this.store.isLoaded && this.queryMode == 'remote') {
this.store.addListener('load', function() {
this.store.isLoaded = true;
this.setValue(v);
}, this);
this.store.load();
} else {
this.callOverridden(arguments);
}
}
});

Ext.form.field.ComboBox.override( {
setValue: function(value) {
if( typeof value != 'object' && !Ext.isEmpty(value) && !this.store.isLoaded && this.queryMode == 'remote') {
value = (value && value.toString) ? value.toString() : value;
this.store.addListener('load', function() {
this.store.isLoaded = true;
this.setValue(value);
}, this);
this.store.load();
} else {
this.callOverridden(arguments);
}
}
});

just another override - working for me, using the [form].loadRecord([model]) method.
beware: if you use the opposite way [form].updateReocrd([model]) the values of the options will not use the default delimiter, but just ',' instead.
so - if you have a loadRecord, do something, then call updateRecord an loadrecord later, the selections will got lost, due to the wrong delimiter. taht's why the "lower than 2" comparison is being performed here
Ext.form.field.ComboBox.override( {
setValue: function(v) {
if (this.multiSelect && typeof v != 'undefined' && typeof v.split == 'function'){
if (this.value.length < 2){
this.setValue(v.split(this.delimiter));
}
} else {
this.callOverridden(arguments);
}
}
});

Related

How to change button property when starting a vuex-electron app?

I am working on a vuex-electron application.
There are several buttons on the main page, when clicked, a file is stored in a specific folder, and at the same time, the property of the button turns to [saved], when this [saved] button is clicked again, a message pops up, asking whether to overwrite or not the old file.
But the problem is : when the app is restarted, all of the buttons' property is initialized to [not saved], so, even though the same file has already been stored, when button is clicked, the old file is overwritten without any pop-ups asking whether to overwrite the existing file or not.
I want to change the feature as below:
when the app is restarted, check file existence first, then based on the result, change button property to [saved].
Is this possible?
If possible, where should I add the logic in.
I am a complete beginner on vue.js.
Have been looking up for a while, but did not find any useful information.
From the following thread, learned that state data is stored in a json file, does this mean I need to change the state? Currently, button properties are not saved in this json file.
Where is the state of a Electron-Vue application stored?
//code
v-for="(btn,i) in buttons" :key="i" #click="save(btn)"
computed: {
buttons() {
let r = this.$store.state.App.aData.filter(x=> {
if (this.aType==='abc') {
return x.video.toString() === '1'
} else {
return !x.video
}
}).map(x => {
let y = this.$copy(x)
y.saved = this.savedData.includes(x.index)
y.disabled = this.appState !== 'def'
return y
})
let index = this.aType==='abc'?998:999
r.push({
index,
a_name:'others',
e_number:this.aType==='abc'?'N':'999',
disabled: this.appState !== 'def',
saved: this.savedData.includes(index),
video:''
})
return r
},
},
methods:{
save(btn) {
if (btn.disabled) {
return
}
if (btn.saved) {
this.$buefy.dialog.confirm({
message: '??',
confirmText: 'overwrite?',
cancelText: 'cancel',
type: 'is-danger',
hasIcon: true,
onConfirm: () => {
if (this.aType==='xyz') {
this.saveXyz(btn)
}
if (this.aType==='abc') {
this.saveAbc(btn)
}
}
})
return
}
if (this.aType==='xyz') {
this.saveXyz(btn)
}
if (this.shootingType==='abc') {
this.saveAbc(btn)
}
},
saveXyz(data) {
if (this.xyzBuffer) {
//create a file and store to a folder
this.savedData.push(data.index)
let idx = this.$store.state.App.aData.findIndex(x=>x.index===data.index)
if (idx > -1) {
idx++
if (idx < this.$store.state.App.aData.length) {
this.selectedData = idx
this.aType = this.$store.state.App.aData[this.selectedData].video ? 'abc' : 'xyz'
this.scrollTo(this.selectedData)
}
}
this.cancel()
})
}
}
},
saveAbc(data) {
if (this.recording) {
return
}
//create a file and store to a folder
this.savedData.push(data.index)
let idx = this.$store.state.App.aData.findIndex(x=>x.index===data.index)
if (idx > -1) {
idx++
if (idx < this.$store.state.App.aData.length) {
this.selectedData = idx
this.aType = this.$store.state.App.aData[this.selectedData].video ? 'abc' : 'xyz'
this.scrollTo(this.selectedData)
}
}
this.cancel()
}
})
},
},

Add a custom button in column header dropdown menus {EXTJS 4}

I want a button in column header dropdown menu of grid in extjs4.
so that i can add or delete columns which are linked in database.
Any help will be appreciated...
Thankyou..:)
Couple of months ago I had the same problem. I've managed to solve it by extending Ext.grid.header.Container (I've overrided getMenuItems method). However, recently, I've found another solution which requires less coding: just add menu item manualy after grid widget is created.
I'll post the second solution here:
Ext.create('Ext.grid.Panel', {
// ...
listeners: {
afterrender: function() {
var menu = this.headerCt.getMenu();
menu.add([{
text: 'Custom Item',
handler: function() {
var columnDataIndex = menu.activeHeader.dataIndex;
alert('custom item for column "'+columnDataIndex+'" was pressed');
}
}]);
}
}
});
Here is demo.​
UPDATE
Here is demo for ExtJs4.1.
From what I have been seeing, you should avoid the afterrender event.
Context:
The application I am building uses a store with a dynamic model. I want my grid to have a customizable model that is fetched from the server (So I can have customizable columns for my customizable grid).
Since the header wasn't available to be modified (since the store gets reloaded and destroys the existing menu that I modified - using the example above). An alternate solution that has the same effect can be executed as such:
Ext.create('Ext.grid.Panel', {
// ...
initComponent: function () {
// renders the header and header menu
this.callParent(arguments);
// now you have access to the header - set an event on the header itself
this.headerCt.on('menucreate', function (cmp, menu, eOpts) {
this.createHeaderMenu(menu);
}, this);
},
createHeaderMenu: function (menu) {
menu.removeAll();
menu.add([
// { custom item here }
// { custom item here }
// { custom item here }
// { custom item here }
]);
}
});
For people who would like to have not just one "standard" column menu but have an individual columnwise like me, may use the following
initComponent: function ()
{
// renders the header and header menu
this.callParent(arguments);
// now you have access to the header - set an event on the header itself
this.headerCt.on('menucreate', function (cmp, menu, eOpts) {
menu.on('beforeshow', this.showHeaderMenu);
}, this);
},
showHeaderMenu: function (menu, eOpts)
{
//define array to store added compoents in
if(this.myAddedComponents === undefined)
{
this.myAddedComponents = new Array();
}
var columnDataIndex = menu.activeHeader.dataIndex,
customMenuComponents = this.myAddedComponents.length;
//remove components if any added
if(customMenuComponents > 0)
{
for(var i = 0; i < customMenuComponents; i++)
{
menu.remove(this.myAddedComponents[i][0].getItemId());
}
this.myAddedComponents.splice(0, customMenuComponents);
}
//add components by column index
switch(columnDataIndex)
{
case 'xyz': this.myAddedComponents.push(menu.add([{
text: 'Custom Item'}]));
break;
}
}
I took #nobbler's answer an created a plugin for this:
Ext.define('Ext.grid.CustomGridColumnMenu', {
extend: 'Ext.AbstractPlugin',
init: function (component) {
var me = this;
me.customMenuItemsCache = [];
component.headerCt.on('menucreate', function (cmp, menu) {
menu.on('beforeshow', me.showHeaderMenu, me);
}, me);
},
showHeaderMenu: function (menu) {
var me = this;
me.removeCustomMenuItems(menu);
me.addCustomMenuitems(menu);
},
removeCustomMenuItems: function (menu) {
var me = this,
menuItem;
while (menuItem = me.customMenuItemsCache.pop()) {
menu.remove(menuItem.getItemId(), false);
}
},
addCustomMenuitems: function (menu) {
var me = this,
renderedItems;
var menuItems = menu.activeHeader.customMenu || [];
if (menuItems.length > 0) {
if (menu.activeHeader.renderedCustomMenuItems === undefined) {
renderedItems = menu.add(menuItems);
menu.activeHeader.renderedCustomMenuItems = renderedItems;
} else {
renderedItems = menu.activeHeader.renderedCustomMenuItems;
menu.add(renderedItems);
}
Ext.each(renderedItems, function (renderedMenuItem) {
me.customMenuItemsCache.push(renderedMenuItem);
});
}
}
});
This is the way you use it (customMenu in the column config let you define your menu):
Ext.define('MyGrid', {
extend: 'Ext.grid.Panel',
plugins: ['Ext.grid.CustomGridColumnMenu'],
columns: [
{
dataIndex: 'name',
customMenu: [
{
text: 'My menu item',
menu: [
{
text: 'My submenu item'
}
]
}
]
}
]
});
The way this plugin works also solves an issue, that the other implementations ran into. Since the custom menu items are created only once for each column (caching of the already rendered version) it will not forget if it was checked before or not.

In an ExtJS Grid, how do I get access to the data store fields that are part of the sort set

How do I get access to the columns/datastore fields that are part of the sort set.
I am looking to modify the a grid's sort parameters for remote sorting. I need the remote sort param's sort key to match the column's field's mapping property. I need these things to happen though the normal 'column header click sorts the data' functionality.
Remote sorting and field mapping (ExtJS 4.1)
This functionality seems not to be implemented in ExtJS. Here is a solution using the encodeSorters function provided since ExtJS 4. Accessing fields map throught the model's prototype is a bit dirty but it does the job :
var store = Ext.create('Ext.data.Store', {
...,
proxy: {
...,
encodeSorters: function (sorters) {
var model = store.proxy.model,
map = model.prototype.fields.map;
return Ext.encode(Ext.Array.map(sorters, function (sorter) {
return {
property : map[sorter.property].mapping || sorter.property,
direction: sorter.direction
};
}));
}
}
});
However, it would be more relevant to override the original method :
Ext.data.proxy.Server.override({
encodeSorters: function(sorters) {
var min, map = this.model.prototype.fields.map;
min = Ext.Array.map(sorters, function (sorter) {
return {
property : map[sorter.property].mapping || sorter.property,
direction: sorter.direction
};
});
return this.applyEncoding(min);
}
});
Assuming you are using simpleSortMode, you could do something like this in your store.
listeners: {
beforeload: function( store, operation, eOpts ) {
if (store.sorters.length > 0) {
var sorter = store.sorters.getAt(0),
dir = sorter.direction,
prop = sorter.property,
fields = store.model.getFields(),
i,
applyProp = prop;
for (i = 0; i < fields.length; i++) {
if (fields[i].name == prop) {
applyProp = fields[i].mapping || prop;
break;
}
}
//clearing the sorters since the simpleSortMode is true so there will be only one sorter
store.sorters.clear();
store.sorters.insert(0, applyProp, new Ext.util.Sorter({
property : applyProp,
direction: dir
}));
}
}
},

Problem with list search in sencha

I am using search option in the list . There is provision to add new items to the list. The problem is that when I add a new item to the list, the list is getting updated , but I cannot search that item through the search field. But after refreshing the browser, we can. But it is not possible to refresh browser each time....... Is there any solution for this problem?
Here is the code I am using to search the list.
xtype: 'searchfield',
placeHolder: 'Search',
name: 'searchfield',
id:'subListSearch',
listeners : {
scope: this,
'focus': function() {
Ext.getCmp('xbtn').show();
},
keyup: function(field) {
var value = field.getValue();
if (!value) {
Store.filterBy(function() {
return true;
});
} else {
var searches = value.split(' '),
regexps = [],
i;
for (i = 0; i < searches.length; i++) {
if (!searches[i]) return;
regexps.push(new RegExp(searches[i], 'i'));
};
Store.filterBy(function(record) {
var matched = [];
for (i = 0; i < regexps.length; i++) {
var search = regexps[i];
if (record.get('Name').match(search)) matched.push(true);
else matched.push(false);
};
if (regexps.length > 1 && matched.indexOf(false) != -1) {
return false;
} else {
return matched[0];
}
});
}
}
}
There is also some other problems. I using some provision to filter the list. But when I uses the search option, it is searching through the entire list, not the filtered list.why?
Thanks
Arun A G
Thanks for responding to my question .
The problem is fixed with bindStore() method. Earlier I was doing load() method to render the new data into the store. But we can not search the last entered item with this method. After binding the Changed store into the list with bindStore() method, the issue was solved.

Extjs 4.x - CheckboxModel to get checked and unchecked value

I have used check box model in the grid panel. When i checked the check box i am the checked column value. Now what i need is when i unchecked i need to get that same unchecked value.
var selModel = Ext.create('Ext.selection.CheckboxModel', {
checkOnly: true,
listeners: {
selectionchange: function(model, records) {
if (records[0]) {
id = records[0].get('id');
alert(id);
}
}
}
});
Thanks in advance.
Regards,
Riyaz
This is the answer:
var selModel = Ext.create('Ext.selection.CheckboxModel', {
checkOnly: true,
listeners: {
deselect: function(model, record, index) {
id = record.get('id');
alert(id);
},
select: function(model, record, index) {
id = record.get('id');
alert(id);
}
}
})