ExtJS checkcolumns cannot edit after modify model - javascript

Hi I tried to edit data before the data store into grid because I have to calculate some values.
I modified the model field like this
fields: ['name', 'email', 'phone',
{
name: 'check',
convert: function(value, record) {
return 1;
}
}
]
and bind dataIndex to the column
columns: [{
...
}
}, {
...
}, {
xtype: 'checkcolumn',
text: 'Phone',
dataIndex: 'check'
}]
When I execute this I found the checkcolumn cannot be editable. What's wrong about this?
Sample

Thats because you always return 1. You need to do for example:
name: 'check',
mapping: 'phone',
convert: function(value, record) {
return value ? 1 : 0;
}

Your problem is the convert function. Your checkcolumn is still active, but each time your value is evaluated, it gets sent through the convert function and returns 1 (or true since it's used in a checkbox)
From what I gather, you want to set a defaultValue on the check column, then you should work with the defaultValue property defining your check column
Here you can learn more about the model itself :)
https://docs.sencha.com/extjs/5.1/5.1.1-apidocs/#!/api/Ext.data.Model
For the field configurations, you could check here
https://docs.sencha.com/extjs/5.1/5.1.1-apidocs/#!/api/Ext.data.field.Field
So, either toss your convert function, or let it return the correct value (true or false, 1 or 0) based on the value parameter in your convert function.

When you click the checkfield the converter is automatically invoked and in your convert:function you always force his value to checked.
Try to set a value with different check or remove the custom converter
here is your fiddle modified:
https://fiddle.sencha.com/#fiddle/12p5
and the fiddle code:
Ext.application({
name: 'Fiddle',
launch: function() {
var store = Ext.create('Ext.data.Store', {
fields: ['name', 'email', 'phone', {
name: 'check',
convert: function(value, record) {
debugger; //You can see that this function is invoked when you check the column
return value ? 1 : 0; //Modify the logic or don't force the value
}
}],
data: [{
name: 'Lisa',
email: 'lisa#simpsons.com',
phone: '555-111-1224',
check: 1 //initialize with checked if necessary
}, {
name: 'Bart',
email: 'bart#simpsons.com',
phone: '555-222-1234',
check: 1
}, {
name: 'Homer',
email: 'homer#simpsons.com',
phone: '555-222-1244',
check: 1
}, {
name: 'Marge',
email: 'marge#simpsons.com',
phone: '555-222-1254',
check: 1
}]
});
Ext.create('Ext.grid.Panel', {
title: 'Simpsons',
store: store,
height: 200,
width: 400,
renderTo: Ext.getBody(),
columns: [{
text: 'Name',
dataIndex: 'name',
renderer: function(value, meta) {
meta.tdCls += ' image-hover';
return '<span class="name">' + value + '</span><img src="http://sstatic.net/stackoverflow/img/icon-16.png" />';
}
}, {
text: 'Email',
dataIndex: 'email',
flex: 1
}, {
xtype: 'checkcolumn',
text: 'Phone',
dataIndex: 'check'
}]
});
}
});

Ran across this same issue. If you change
return value ? 1 : 0;
to
if(value = [value to check box] || value = true) {return true;}
else {return false;}
Probably a fancier way to do it but this will take care of hitting the convert function when a user clicks the checkbox column.

Related

ExtJS 5: Parent model convert dependency on Child association

I have 2 models... a Parent and a Child... a Parent hasMany Child models. In the Child, I have a field that is created by using its data (in this example, it's just converting and returning 1). In the Parent, I have two conversions going on... one uses its data, and the 2nd one depends on the Child's data. However, when creating the Parent model, it appears the Child association isn't fully baked yet, but when I go to update the Parent model with a new value, the Child association is there.
Basically, what I want to know is, when you see the Total2 console firing, I want Test to be populated. How do I force the associations to be read before using my conversion functions in the parent? And ideally, if there's a change in the Child, the dependent conversion function in Parent will automatically fire... I realize that most likely won't be possible, but it would be an incredible added bonus.
Here's my example.
app.js
Ext.application({
name : 'Fiddle',
launch : function() {
var store = Ext.create('Ext.data.Store', {
model: 'Namespace.model.Parent',
autoLoad: true,
listeners: {
load: onLoadStore
}
});
var grid = Ext.create('Ext.grid.Panel', {
title: 'associations',
store: store,
renderTo: Ext.getBody(),
columns: [{
text: 'Primary Key',
dataIndex: 'PrimaryKey'
}]
});
function onLoadStore(store, records, successful, eOpts) {
var firstGroups = store.first().getGroupsStore();
console.log('before', firstGroups.getCount(), firstGroups.isLoaded());
firstGroups.first().set('GroupName', 'blah');
store.first().set('blank', 1)
}
}
});
Parent
Ext.define('Namespace.model.Parent', {
extend: 'Ext.data.Model',
alias: 'model.parent',
requires: [
'Ext.data.field.Integer',
'Ext.data.field.String',
'Namespace.model.Child'
],
idProperty: "PrimaryKey",
fields: [{
type: 'string',
name: 'PrimaryKey',
critical: true
}, {
type: 'string',
name: 'Title'
}, {
type: 'int',
name: 'Rating',
defaultValue: 2
}, {
type: 'int',
name: 'Total',
depends: ['Rating'],
convert: function(value, record) {
console.log('Total', record)
return record.get('Rating') * 2;
}
}, {
name: 'Total2',
type: 'int',
depends: ['groupsMapping', 'blank'],
// depends on child's Test property
convert: function(value, record) {
var groupsMapping = record.get('groupsMapping');
if (groupsMapping) {
for (var i = 0; i < groupsMapping.length; i++) {
console.log('Total2', groupsMapping[i].GroupName, groupsMapping[i].Test);
}
}
return 0;
}
}, {
name: 'groupsMapping',
type: 'auto',
mapping: 'Groups'
}, {
name: 'blank',
type: 'int'
}],
hasMany: [{
model: 'Namespace.model.Child',
associationKey: 'Groups',
name: 'getGroupsStore'
}],
proxy: {
type: 'ajax',
url: 'data1.json'
}
});
Child
Ext.define('Namespace.model.Child', {
extend: 'Ext.data.Model',
alias: 'model.child',
fields: [{
type: 'int',
name: 'GroupInt',
critical: true
}, {
type: 'string',
name: 'GroupName'
}, {
name: 'Test',
type: 'int',
depends: ['GroupName'],
convert: function() {
console.log('Test, parent depends on this')
return 1;
}
}],
proxy: {
type: 'memory'
}
});
I've hit the same problem and took me some time in order to realise that the associations are not available on conversion time
Like in your example, I was sending the child records together with the parent ones (nested) and have 'manually' built a fake store using child model & parent field child data in order to do my math for the conversion / calculation, which did the trick:
{
name: 'validationScore',
depends: ['childRecords'],
type: 'number',
persist: false,
convertOnSet: true,
convert: function(val, rec){
// here we have access only to direct record field, and not the association association !
// we can use data directly in the calculation
children = rec.get('childRecords');
// or build a fake store in order to easily parse them
children = Ext.create('Ext.data.Store', {
model: 'Namespace.model.ChildModel',
data: rec.get('childRecords')
})
// ... calculate whatever
return result;
}
}
But now my 'new' challenge is to figure it out a (good) solution to update the converted value upon child records' changes ...
I did something similar to qdev, except I listened on the actual association's store. There's something funky about the constructor though... if I didn't put that timeout in there, then I would get an error with trying to access the first record in the store load... might be a framework bug, or I'm doing something terrible. The important code is the constructor and calculate method... in the app, I just have a 1 second timeout on changing the child data... you can see the grid's row data change from 3 to 102. Here's an updated example:
constructor: function(config) {
this.callParent(arguments);
var me = this;
setTimeout(function() {
var groupsStore = me.getGroupsStore();
if (groupsStore) {
groupsStore.on('update', me.calculateChanges, me);
groupsStore.on('datachanged', me.calculateChanges, me);
}
me.calculateChanges();
}, 1);
},
calculateChanges: function() {
console.log('calculating');
var groupsStore = this.getGroupsStore();
if (groupsStore) {
var total2 = 0;
groupsStore.each(function(group) {
total2 += group.get('Test');
});
this.set('Total2', total2);
}
},

uncheck overall radiogroup radio field during load in extjs 4

Here the radio field in the radio group usually select based on the previous selection. i.e., when refresh the page it automatically set the previous value. But i need to clear the over all values from radio group.
this.mcmAdminServiceIndicatorsRadioGroup = new Ext.form.RadioGroup({
width: 350,
height: 50,
items: [
{
xtype: 'radiofield',
name: 'serviceIndicator',
fieldLabel: '',
inputValue: 'ADM',
boxLabel: 'ADM'
},
{
xtype: 'radiofield',
name: 'serviceIndicator',
margin: '0 0 0 20',
fieldLabel: '',
inputValue: 'BCK',
boxLabel: 'BCK'
},
{
xtype: 'radiofield',
name: 'serviceIndicator',
margin: '0 0 0 20',
fieldLabel: '',
inputValue: 'CKC',
boxLabel: 'CKC'
},
{
xtype: 'radiofield',
name: 'serviceIndicator',
margin: '0 0 0 20',
fieldLabel: '',
inputValue: 'BRK',
boxLabel: 'BRK'
},
{
xtype: 'radiofield',
name: 'serviceIndicator',
margin: '0 0 0 20',
fieldLabel: '',
inputValue: 'FMF',
boxLabel: 'FMF'
}
]
});
am tried these three ways inside the listner of the other radio group component..
this.mcmTaskCategoryRadiogroup = new Ext.form.RadioGroup({
width: 205,
height: 50,
items: [
{
xtype: 'radiofield',
name: 'type',
inputValue: 'Customer',
boxLabel: 'Customer',
checked: true
},
{
xtype: 'radiofield',
name: 'type',
inputValue: 'Admin',
boxLabel: 'Admin'
}
],
listeners: {
scope: this,
change: function(radiogroup, newValue, oldValue) { //will be trigger twice, one with both fields, and second with the new field
if(typeof(newValue.type) == 'string') {
if(newValue.type === 'Admin') {
this.mcmPassengerFieldSet.hide();
this.mcmPassengerServiceIndicatorsFieldSet.hide();
this.mcmAdminServiceIndicatorsFieldSet.show();
this.mcmRequestTypeCombobox.store.loadData([{ name: 'Admin' }], false);
this.mcmRequestTypeCombobox.setValue('Admin');
//this.mcmAdminServiceIndicatorsRadioGroup.setValue(false);
//this.mcmAdminServiceIndicatorsRadioGroup.setValue({ serviceIndicator: taskType });
this.mcmAdminServiceIndicatorsRadioGroup.items.items[0].setValue(true);
} else if(newValue.type === 'Customer') {
this.mcmPassengerFieldSet.show();
this.mcmPassengerServiceIndicatorsFieldSet.show();
this.mcmAdminServiceIndicatorsFieldSet.hide();
this.mcmRequestTypeCombobox.store.loadData([
{ name: '5Star' },
{ name: '5Key' },
{ name: 'Concierge Key' },
{ name: 'Focus Market' },
{ name: 'Sales' },
{ name: 'OA VIP' },
// TCS:09-24-2013 modified
{ name: 'JL VIP' },
{ name: 'BA VIP' },
{ name: 'IB VIP' },
{ name: 'QF VIP' },
// modification ended
{ name: 'Other' }
], false);
this.mcmRequestTypeCombobox.setValue(
this.mcmDisplayedRecord.get('RequestType') ? this.mcmDisplayedRecord.get('RequestType') : 'Other');
}
}
}
}
});
Have you tried removing the 'checked : true' from the Customer radiofield?
David
I think this is a bug of Ext JS. The below code is a reset function source code present in "Ext.form.field.Field" class.
reset : function(){
var me = this;
me.beforeReset();
me.setValue(me.originalValue);
me.clearInvalid();
// delete here so we reset back to the original state
delete me.wasValid;
}
Explanation:
The above function set the field value as actual original value of the field. This is working fine for all other types except "radio". The "checked:false" setting is also not working even though the base class for radio is "checkbox"(works fine for checkbox).
Problem
I think the problem is occurred after selecting any one of the options of radio/radiogroup. The radio component needs to maintain the original value properly but whenever we checked/unchecked, the original value of the radio component is changed. Thats is the reason the reset function is failed to reset the radio.
Hack
I did a hack for this problem. I am maintaing one more key for holding my original value of the radio and I manually set the value whenever I call the reset function. I have overriden the above function like this.
reset : function(){
var me = this;
me.beforeReset();
me.setValue(me.initialDefaultValue);
me.clearInvalid();
// delete here so we reset back to the original state
delete me.wasValid;
}
Now I can create a radio button something like this,
{xype: 'radio', name: 'Test', initialDefaultValue: false, boxLabel: 'Hello'}
The above solution will work fine even If you reset entire form values by calling form.reset().
Hope this help..!

Making sure an ExtJS checkboxfield updates its model

I have inherited an ExtJs4 project, and I've got a fairly basic question.
I have a view that has a newly added checkbox field as one of the items, like so:
{
boxLabel: 'Test Message?',
xtype: 'checkboxfield',
id: 'cbTextMessage',
checked: false,
name: 'testMessage',
inputValue: true,
uncheckedValue: false
}
When the record is active, this value changes to the appropriate checked or unchecked state. When creating a new record, the value is set to the value of the checkbox. However, when editing an existing record, the model never gets updated to any value other than the original value.
The model:
Ext.define('PushAdmin.model.Message', {
extend: 'Ext.data.Model',
idProperty: 'id',
requires: ['Proxy.ParameterProxy'],
fields: [
{ name: 'id', type: 'int' },
{ name: 'games', type: 'auto',
convert: function(data, model) {
data = ( data && !Ext.isArray(data) ) ? [data] : data;
return data;
}
},
{ name: 'msgEnglish', type: 'string' },
{ name: 'msgFrench', type: 'string' },
{ name: 'msgSpanish', type: 'string' },
{ name: 'testMessage', type: 'bool' },
{ name: 'sendAt', type: 'date' },
{ name: 'note', type: 'string'},
{ name: 'status', type: 'string' },
],
proxy: {
type: 'rest',
url: '/apnsadmin/rest/Message',
pageParam: undefined,
startParam: undefined,
limitParam: undefined,
reader: {
type: 'json',
root: 'data',
successProperty: 'success'
}
}
});
And finally this is the function that gets called when the save button is clicked.
click: function () {
var grid = this.getQueuedMessagesGrid();
var sm = grid.getSelectionModel();
var selectedRecord = sm.getCount() > 0 ? sm.getSelection()[0] : undefined;
this.getMessageForm().getForm().updateRecord();
var newRecord = this.getMessageForm().getForm().getRecord();
if (selectedRecord!=undefined) {
console.log(selectedRecord);
console.log(newRecord);
selectedRecord.save();
} else {
// New record!
console.log("Saving new record");
grid.getStore().add(newRecord);
newRecord.save();
}
this.getMessageForm().setDisabled(true);
this.getMessageForm().getForm().reset();
}
},
I am aware that things are probably not the proper ExtJS way to do things, but since this is mostly working I am trying not to have to rewrite large chunks of it. I'd just like to know what I'm doing wrong in adding this checkbox/boolean field to the form.

Grid loses (visible) selection after store-record edit and after commit

I have a simple case where I got a grid with an attached store.
There are 2 buttons. One with a handler that modifies the selected record. One with a handler that commits the selected record.
When I select a record and push edit -> editing takes place selection (looks lost) if you call grid.geSelectionModel().getSelection() you will see that the record is still selected. It just doesn't show it that way.
You can't select it again, you first have to select another record, and select the record back.
Secondly when you select a record click on the commit button, the value is committed, but the selection 'appears' again as lost.
Is this a bug? How can I fix this? I want it to keep the selection visible!
Here is a fiddle
and here is the sample code: (I use Ext 4.1.1)
var cellEditing = Ext.create('Ext.grid.plugin.CellEditing', {
clicksToEdit: 1
});
Ext.create('Ext.data.Store', {
storeId: 'simpsonsStore',
fields: ['name', 'email', 'phone'],
data: {
'items': [{
'name': 'Lisa',
"email": "lisa#simpsons.com",
"phone": "555-111-1224"
}, {
'name': 'Bart',
"email": "bart#simpsons.com",
"phone": "555-222-1234"
}, {
'name': 'Homer',
"email": "home#simpsons.com",
"phone": "555-222-1244"
}, {
'name': 'Marge',
"email": "marge#simpsons.com",
"phone": "555-222-1254"
}]
},
proxy: {
type: 'memory',
reader: {
type: 'json',
root: 'items'
}
}
});
Ext.create('Ext.container.Container', {
layout: 'fit',
renderTo: Ext.getBody(),
items: [{
xtype: 'grid',
store: Ext.data.StoreManager.lookup('simpsonsStore'),
columns: [{
text: 'Name',
dataIndex: 'name'
}, {
text: 'Email',
dataIndex: 'email',
flex: 1
}, {
text: 'Phone',
dataIndex: 'phone'
}],
height: 200,
buttons: [{
text: 'commit selection',
handler: function(){
this.up('grid').getSelectionModel().getSelection()[0].commit();
}
},{
text: 'set selection name to maggy',
handler: function(){
this.up('grid').getSelectionModel().getSelection()[0].set('name', 'Maggy');
}
}]
}]
});​
UPDATE:
I reported it on the sencha forum. Mitchel Simoens told me it's fixed in Ext 4.1.2. Too bad it's a 'Support subscriber only' version..
UPDATE:
I'm locating the issue to try and fix it. I believe the issue is located in the Ext.view.Table class in onUpdate method, more precise around this piece of code:
if (oldRowDom.mergeAttributes) {
oldRowDom.mergeAttributes(newRow, true);
} else {
newAttrs = newRow.attributes;
attLen = newAttrs.length;
for (i = 0; i < attLen; i++) {
attName = newAttrs[i].name;
if (attName !== 'id') {
oldRowDom.setAttribute(attName, newAttrs[i].value);
}
}
}
Is it a bad idea to just leave this piece of code out? I commented it out it seems like it's working now, but won't it break some other functionality? http://jsfiddle.net/Vandeplas/YZqch/10/
I think its a bug, maybe as part of refreshing the grid to show the dirty bits.
I circumvented this in an ugly way, in your revised fiddle:
{
text: 'set selection name to maggy',
handler: function(){
var sel = this.up('grid').getSelectionModel();
var rec = sel.getSelection()[0];
rec.set('name', 'Maggy');
sel.deselectAll();
sel.select(rec.index);
}
}
I did this for .set(), but the same can be done for commit()
Hope this helps somewhat.

How to filter data using javascript, jquery, or some other javascript framework?

As an example, I have 3 check boxes:
<input type="checkbox" name="filter[]" value="1">
<input type="checkbox" name="filter[]" value="2">
<input type="checkbox" name="filter[]" value="3">
I'm using PHP to send in some json, like so:
{'name': 'John Doe', 'title': 'CEO', 'filters': {'1':'2', '2':'3'}},
{'name': 'Jane Doe', 'title': 'COO', 'filters': {'1':'1', '2':'3'}},
{'name': 'Tim Doe', 'title': 'CFO', 'filters': {'1':'2'}}
I'm trying to figure out how to click on the checkboxes and only show records with the corresponding filters. Is there something in jquery that would make that simple, or maybe a framework like Backbone or Knockout? I've seen on example in Knockout, and it seemed needlessly complex... but maybe it IS more complex than I'm thinking it should be.
Thanks for any help, or being able to point me in the right direction.
edit - I'm totally open to reformatting the json, if that makes this easier.
I'm a bit unsure of the filter object you send, but I guess it is the values you want to filter and not the keys. And I also guess that the response is an array with objects.
First I would create an array that the checkboxes add and remove values to. Showing of one input here, but all should point to the same array:
var filterArray = [];
var input = document.createElement("INPUT");
input.value = "1";
input.onclick = function() {
if (this.checked)
filterArray.push(this.value); // Add value to array
else
filterArray.splice(filterArray.indexOf(this.value), 1); // Remove value from Array
filterPersons(); // Run the filter function
}
Then I would run something like this:
function filterPersons() {
var persons = phpResponse;
var result = [];
for (var x = 0; x < persons.length; x++) {
var personFilters = persons[x].filters;
for (var filter in personFilters) {
if (personFilters.hasOwnProperty(filter) && filterArray.indexOf(personFilters[filter]) >= 0) // Check if value is in filterArray
result.push(persons[x]); // Add person to a result array
}
displayResult(result); // Display the result somewhere
}
This would also make it work "on the fly", when you click the checkboxes.
Take a look on to ExtJS. It has the object "store", which is able to store structured data and allow to do manipulations with it, like sorting, filtering, querying.
For example your task could be resolved like that:
Ext.application({
name: 'HelloExt',
launch: function() {
Ext.create('Ext.data.Store', {
storeId:'UsersStore',
model: 'User',
fields: [ 'id', 'name', 'title', 'filter1', 'filter2', 'filter3' ],
data: [
{ name: 'Ed', title: 'CEO', filter1: true, filter2: false, filter3: true },
{ name: 'Tommy', title: 'CTO', filter1: false, filter2: false, filter3: false },
{ name: 'Aaron', title: 'COO', filter1: true, filter2: true, filter3: true },
{ name: 'Jamie', title: 'CFO', filter1: true, filter2: true, filter3: false }
]
});
function filterStore() {
var store = Ext.data.StoreManager.lookup('UsersStore');
store.clearFilter();
store.filter([
{ property: 'filter1', value: Ext.getCmp('Filter1CB').getValue() },
{ property: 'filter2', value: Ext.getCmp('Filter2CB').getValue() },
{ property: 'filter3', value: Ext.getCmp('Filter3CB').getValue() }
]);
}
Ext.create('Ext.container.Viewport', {
layout: 'vbox',
layoutConfig: {
vbox: {
align: 'stretch'
}
},
items: [
{
xtype: 'panel',
border: false,
padding: 10,
items: {
flex: 1,
xtype: 'fieldcontainer',
items: [
{ fieldLabel: 'Filter1', xtype: 'checkbox', id: 'Filter1CB', handler: filterStore },
{ fieldLabel: 'Filter2', xtype: 'checkbox', id: 'Filter2CB', handler: filterStore },
{ fieldLabel: 'Filter3', xtype: 'checkbox', id: 'Filter3CB', handler: filterStore }
]
}
},
{
flex: 1,
xtype: 'gridpanel',
title: 'Users',
store: Ext.data.StoreManager.lookup('UsersStore'),
columns: [
{ header: 'Name', dataIndex: 'name' },
{ header: 'Title', dataIndex: 'title' }
]
}
]
});
}
});
Fiddle: http://jsfiddle.net/Q55ym/1/
You mean loop through the JSON to find only the entries with the filter?
First, change filters in the JSON to 'filters':'1' or 'filters':'12' or 'filters':'13' or whatever. Just put the filters into 1 string.
Then use this:
function filter(){
var loadedJSON; // load the json from php here,
//sort 'filter' by number from smallest to largest
//(so '312' becomes '123')
for(var i in loadedJSON){
String check="";
if($("checkbox[name='filter[]'][value='1']").is(":checked"))check="1";
if($("checkbox[name='filter[]'][value='2']").is(":checked"))check+="2";
if($("checkbox[name='filter[]'][value='3']").is(":checked"))check+="3";
if(i.filters.indexOf(check)>-1) // passed filters
}
}
I used jquery to determine if the checkboxes are checked, but you could also do document.getElementsByName('filter[]')[0].checked

Categories

Resources