How to dynamic set different tpl for widgetcolumn - extjs

friends!
I have a grid, with a widget column. I get the data for the store from the server.
I get different templates for each row and try to set these templates in my widget. However, I am not able to display the data in the templates.
Here is my example fiddle https://fiddle.sencha.com/#fiddle/3j41&view/editor
I expect the second column to display data with different templates. Instead of data I see {testName}.
In the third column everything works, but it's static data
Can you help me understand what's wrong?
My result:
My store:
var store = Ext.create('Ext.data.Store', {
fields: ['name', 'tplConfig'],
data: [{
name: 'Test 1',
tplConfig: {
tplBody: '<div><b>Name:</b> {testName}</div> <div>any text</div>',
tplData: {
testName: 'Alex'
}
}
} ]
});
My grid:
{
xtype: 'grid',
title: 'Widget Column Demo',
store: store,
columns: [
.....
{
xtype: 'widgetcolumn',
text: 'Dynamic',
width: 120,
dataIndex: 'tplConfig',
widget: {
xtype: 'component',
tpl: '{tplBody}',
//data: '{tplData}' //it's not working
}
}
.......
]
}

You can use renderer:
{
xtype: 'gridcolumn',
text: 'Dynamic',
width: 120,
dataIndex: 'tplConfig',
renderer: function(tplConfig) {
var t = new Ext.Template(tplConfig.tplBody);
return t.apply(tplConfig.tplData);
}
}
or as a 1 liner:
return new Ext.Template(tplConfig.tplBody).apply(tplConfig.tplData);

Related

How to dynamically add columns for Grid ExtJs

I want dynamically load columns for grid from loaded store.
I used code like in sencha fiddle https://fiddle.sencha.com/#fiddle/lc5&view/editor, it work, but in modern version it dose not work. Because modern version not have reconfigure method.
How can I solve that problem.
Based on your example, the solution is as follows:
var grid = Ext.create({
xtype: 'grid',
fullscreen: true,
minHeight: 150,
renderTo: document.body,
plugins: {
gridsummaryrow: true
},
store: {
fields: ['student', 'mark'],
idProperty: 'student',
data: [{
"student": 'Student 1',
"mark": 84
}, {
"student": 'Student 2',
"mark": 72
}, {
"student": 'Student 3',
"mark": 96
}, {
"student": 'Student 4',
"mark": 68
}],
proxy: {
type: 'memory'
}
},
columns: [{
dataIndex: 'student',
text: 'Name'
}]
});
grid.getStore().load();
grid.setColumns([{
width: 200,
dataIndex: 'student',
text: 'Name',
summaryType: 'count',
summaryRenderer: function(value){
return Ext.String.format('Number of students: {0}', value);
}
}, {
"dataIndex": 'mark',
"text": 'Mark',
"summaryType": 'average'
}]);
the most important
You must define a column on the grid columns, even though it will be changed at a future time on your grid.
I removed the dependency from your students.json sample file and put the data into an in-memory store to facilitate the demonstration here.
In modern version, you will use setColumns method.
Working Sample on fiddle.
Another option I did is to bind the columns after populating them in the controller.
Sample code:
{
xtype: 'gridpanel',
id: 'user-grid',
cls: 'user-grid',
width: '100%',
scrollable: false,
bind: {
store: '{userStore}',
columns: '{columns}'
}
}
In the controller I populated the columns this way:
setUserGridColumns: function () {
var fields = ['title', 'Surname', 'Profession', 'Age', 'randomValue'];// this can come from server
var columns = [];
fields.forEach(element => {
var column = {
xtype: 'gridcolumn',
cls: 'content-column',
dataIndex: element,
text: element,
flex: 1,
sortable: false,
align: 'center',
style: 'border-width:0px !important; margin-bottom:15px'
}
columns.push(column);
});
this.getViewModel().set('columns', columns);
}

Bind store size to table's header

I have ExtJS application and I want to implement displaying total number of records in the header.
ViewModel:
Ext.define('AppName.view.main.MainModel', {
extend: 'Ext.app.ViewModel',
// ...
stores: {
users: Ext.create("AppName.store.UsersStore")
}
});
Binding to view
Ext.define('AppName.view.main.UsersPanel', {
extend: 'Ext.panel.Panel',
// ...
items:[{
bind : {
title : 'Users ({users.data.length})'
},
items: [{
listeners : {
cellclick : 'OnSelectUser'
},
xtype: 'grid', columns: [
{ text: 'Full Name', dataIndex: 'fullName', flex: 2},
{ text: 'Address', dataIndex: 'address', flex: 1},
{ text: 'Sex', dataIndex: 'sex', flex: 1},
{ text: 'Date Of Birth', dataIndex: 'dob', flex: 1}
],
bind: '{users}'
}]
}]
});
And this works after first loading of records to Store by code
OnSearchButtonClick: function () {
var me = this,
usersStore = me.getViewModel().get('users');
usersStore.load();
}
But when I remove records from store by code
var me = this,
usersStore = me.getViewModel().get('users');
usersStore.loadData([], false);
or by
usersStore.removeAll()
then only table is cleared but not header.
So I have a question: how can I bind store size?
try with sync on the store after removing records.
usersStore.removeAll();
usersStore.sync();
sometimes binding not refresh binded components because new or removed records are not synched in the store

ExtJs - Column Editor with different xtype based on record value

I have a gridpanel with rowediting plugin enabled. I was wondering if it is possible to display in the same cell either checkbox control or numberfield based on data that's being returned from server. I have not seen anything like that before and googling has not yield any results so it may be impossible at all. It looks like I have to specify different editor types not per each column but per each cell.
How can I achieve that?
P.S. I must have a chance to edit that cell, i.e. change number value or check/uncheck checkbox.
That is very easy to achieve, you will need to use the getEditor method of your grid column and get it to return the form field you want:
Example:
{
xtype: 'gridcolumn',
getEditor: function(record) {
var grid = this.up('grid'),
cellediting = grid.findPlugin('cellediting'),
editors = cellediting.editors,
editor = editors.getByKey(this.id),
fieldType;
if (editor) {
// Do this to avoid memory leaks
editors.remove(editor);
}
fieldType = isNaN(parseFloat(record.get('salary'))) ? 'textfield' : 'numberfield';
return {
xtype: fieldType,
allowBlank: false
};
},
dataIndex: 'salary',
text: 'Salary',
flex: 1
}
I have created a fiddle demonstrating the use of this method, if the column Salary holds a string it will edit with a textfield, if it holds a number, it will edit with a Numberfield.
Hope it helps
Fiddle: https://fiddle.sencha.com/#fiddle/c2m
My fiddle is working with the CellEditor plugin, you will have to make the adjustments to make it work with your RowEditor plugin, for further reference, check the documentation for Grid Column and the getEditor method.
Many thanks to Guilherme Lopes for the nice code to begin with. Here is the sample of what I finally got:
var data = [{
name: 'Richard Wallace',
age: 24,
hired: '9/21/2013',
active: true,
salary: 1,
checkbox: true
}, {
name: 'Phyllis Diaz',
age: 29,
hired: '1/27/2009',
active: false,
salary: 41244,
checkbox: false
}, {
name: 'Kathryn Kelley',
age: 23,
hired: '9/14/2011',
active: false,
salary: 98599.9,
checkbox: false
}, {
name: 'Annie Willis',
age: 36,
hired: '4/11/2011',
active: true,
salary: 0,
checkbox: true
}];
var store = Ext.create('Ext.data.Store', {
data: data,
fields: [{
name: 'name'
}, {
type: 'float',
name: 'age'
}, {
type: 'date',
name: 'hired'
}, {
type: 'boolean',
name: 'active'
}, {
name: 'salary'
}]
});
Ext.define('MyApp.view.MyGridPanel', {
extend: 'Ext.grid.Panel',
alias: 'widget.mygridpanel',
height: 315,
width: 784,
title: 'Employees',
store: store,
viewConfig: {
listeners: {
beforecellclick: function (view, cell, cellIndex, record, row, rowIndex, e) {
if (cellIndex == 4 && record.get('checkbox')) {
if (record.get('salary')) {
record.set('salary', 0);
} else {
record.set('salary', 1);
}
return false;
}
return true;
}
}
},
columns: [{
xtype: 'gridcolumn',
dataIndex: 'name',
text: 'Name',
flex: 1,
editor: {
xtype: 'textfield'
}
}, {
xtype: 'gridcolumn',
dataIndex: 'age',
text: 'Age'
}, {
xtype: 'datecolumn',
dataIndex: 'hired',
text: 'Hired',
flex: 1
}, {
xtype: 'checkcolumn',
dataIndex: 'active',
text: 'Active'
}, {
xtype: 'gridcolumn',
getEditor: function (record) {
var fieldType = record.get('checkbox') ? 'checkboxfield' : 'textfield';
return Ext.create('Ext.grid.CellEditor', {
field: {
xtype: fieldType,
allowBlank: false
}
});
},
renderer: function (value, metaData) {
if (metaData.record.get('checkbox')) {
if (metaData.record.get('salary')) {
return '<div style="text-align: center"><img class="x-grid-checkcolumn x-grid-checkcolumn-checked" src="data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw=="></div>';
} else {
return '<div style="text-align: center"><img class="x-grid-checkcolumn" src="data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw=="></div>';
}
}
return value;
},
dataIndex: 'salary',
text: 'Salary',
flex: 1
}],
plugins: [{
ptype: 'cellediting',
autoCancel: false,
clicksToEdit: 1
}]
});
Ext.create('MyApp.view.MyGridPanel', {
renderTo: Ext.getBody()
});
Working example on Sencha's fiddle https://fiddle.sencha.com/#fiddle/c3p
Editor contains one field, and this editor is used for the whole column. You can't specify two xtypes or multiple editors for one column.
That said, it is not completely impossible, but it will require some work.
You will have to define a new custom field with custom xtype.
Tell this field to either render a checkboxfield or a numberfield, depending on the value.
This will require you to override/implement most if not all functions that a Ext.form.field.Base has...

EXTJS how to get the component without declare id?

Ext.define('MyApp.view.MyVehicleGridPanel', {
extend: 'Ext.grid.Panel',
alias: 'widget.mygrid',
header: false,
store: UserStore,
multiSelect: false,
columns: [
{
xtype: 'gridcolumn',
dataIndex: '_id',
text: 'Vehicle ID'
},
{
xtype: 'gridcolumn',
width: 126,
dataIndex: 'Plat_No',
text: 'Plat Number'
},
{
xtype: 'gridcolumn',
width: 200,
dataIndex: 'Name',
text: 'Added By'
}
]
})
i dont have any id declare in the gridpanel, because it will used in dynamicly,
so, i m using alias to find my grid component like below code
var grid = Ext.ComponentQuery.query('mygrid');
console.log( Ext.ComponentQuery.query('mygrid') );
if (grid.getSelectionModel().hasSelection()) { //error at here
var row = grid.getSelectionModel().getSelection()[0];
console.log(row.get('Plat_No'));
};
But, firebug return error with TypeError: grid.getSelectionModel is not a function
any other way to find my gridpanel component?
Ext.ComponentQuery.query() returns an array of matched Components from within the passed root object.
So if you have only one mygrid component in your application, you can get your grid like this:
var grid = Ext.ComponentQuery.query('mygrid')[0];

ExtJS 4.2 - Bind Date Picker to Grid - Newbie Q

I am new to ExtJS 4 and struggling at times with the learning curve. I have followed the documentation on sencha's site for MVC concept for basic structure of my app, however I am having difficulty determining where/how to implement certain components/handlers/listeners as I don't quite have the feel for this frame work yet.
So, here is my question.... (Yes I did look at other posts on SO but I think at this point I am too stupid to identify and apply what similar posters may have come accross to solve my issues)
How do I bind a date field in my grid to the date picker date that is selected and vice versa? If I select a date in my date picker I would like to have my grid load relevant rows from my db. If I select a row in my grid I would like to see the date picker reflect the date in the selected row.
Can someone give me a narrative of the approach i should be taking? I have seen some code examples but I don't clearly see an obvious preferred method or the way it should be done. If there is a link someone can give me to look at I will be happy to study.
This is my first post on SO so please forgive me for any etiquette I am lacking as well as other annoying things. Thanks in advance!
Store:
Ext.define('AM.store.Users', {
extend: 'Ext.data.Store',
model: 'AM.model.User',
autoLoad: true,
autoSync:true,
pageSize:50,
proxy:
{
type: 'ajax',
api:
{
read: 'http://192.168.0.103/testit/dao_2.cfc?method=getContent',
update: 'http://192.168.0.103/testit/dao_2-post.cfc?method=postContent'
},
reader:
{
type: 'json',
root: 'data',
successProperty: 'success',
totalProperty : 'dataset'
}}
});
model:
Ext.define('AM.model.User', {
extend: 'Ext.data.Model',
fields: [
{name: 'message_id',type: 'textfield'},
{name: 'recip_email',type: 'textfield'},
{name: 'unix_time_stamp',type:'datefield'}
]
});
View:
Ext.define('AM.view.user.List' ,{
extend: 'Ext.grid.Panel',
alias: 'widget.userlist',
title: 'All Users',
store: 'Users',
plugins:[Ext.create('Ext.grid.plugin.RowEditing', {clicksToEdit: 1})],
dockedItems: [{ xtype: 'pagingtoolbar',
store: 'Users',
dock: 'bottom',
displayMsg: 'Displaying Records {0} - {1} of {2}',
displayInfo: true}],
initComponent: function() {
this.columns = [
Ext.create('Ext.grid.RowNumberer',
{
resizable: true,
resizeHandles:'all',
align: 'center',
minWidth: 35,
maxWidth:50
}),
{
header: 'Name',
dataIndex: 'message_id',
flex: 1,
editor:'textfield',
allowBlank: false,
menuDisabled:true
},
{
header: 'Email',
dataIndex: 'recip_email',
flex: 1,
editor:'textfield',
allowBlank: false,
menuDisabled:true
},
{
header: 'Date Time',
dataIndex: 'unix_time_stamp',
width: 120,
menuDisabled:true,
renderer: Ext.util.Format.dateRenderer('m/d/Y'),
field:{ xtype:'datefield',
autoSync:true,
allowBlank:false,
editor: new Ext.form.DateField(
{format: 'm/d/y'}) }
}];
this.callParent(arguments);
},
});
Viewport:
Ext.Loader.setConfig({enabled:true});
// This array is for testing.
dateArray = ["12/14/2013","12/16/2013","12/18/2013","12/20/2013"];
Ext.application({
requires: ['Ext.container.Viewport'],
name: 'AM',
appFolder: 'app',
controllers: ['Users'],
launch: function() {
Ext.create('Ext.container.Viewport', {
layout: 'border',
items:
[
{
region: 'center',
//layout:'fit',
title:'The Title',
xtype: 'tabpanel', // TabPanel itself has no title
activeTab: 0, // First tab active by default
items:
[{
xtype: 'userlist',
listeners:
{
select: function(selModel, record, index, options)
{
// do something with the selected date
// Ext.Msg.alert(record.data.message_id, record.data.recip_email +'<br> ' + record.data.unix_time_stamp);
}
}
}]
},
{
region: 'west',
layout:'fit',
xtype: 'tabpanel',
activetab:0,
collapsible:false,
split: false,
title: 'The Title',
width:178,
maxWidth:400,
height: 100,
minHeight: 100,
items:
[
{
title: 'Tab 1',
xtype:'panel',
items:
[{
xtype: 'datepicker',
title: 'mydate',
minDate: new Date('12/15/2013'),
maxDate: new Date(),
// Disable dates is set to invert dates in array
disabledDates:["^(?!"+dateArray.join("|")+").*$"],
// disabledDates:["^("+dateArray.join("|")+").*$"],
handler: function(picker, date)
{
// do something with the selected date
Ext.Msg.alert('date picker example in init2.js');
}
}]
},
{
title: 'Tab 2',
html: 'ers may be added dynamically - Others may be added dynamically',
}
]
}
]
});
}
});
Update to Datepicker in Viewport:
One additional note is that i notice a property attribute in the JSON packet that has the date included even without making you suggested changes to the store. I notice there may be a bug in the link you provided?? If i set to false or remove it altogether from my store it has same behavior and is included in my JSON packet.
Do I need to encode the url also? when I click on a row in my grid and hit the update button i recive the grid row on my server side with what appears to be already url encoded by extjs perhaps?
Ext.Loader.setConfig({enabled:true});
// This array is for testing.
dateArray = ["12/14/2013","12/16/2013","12/18/2013","12/20/2013"];
Ext.application({
requires: ['Ext.container.Viewport'],
name: 'AM',
appFolder: 'app',
controllers: ['Users'],
launch: function() {
Ext.create('Ext.container.Viewport', {
layout: 'border',
items:
[
{
region: 'center',
//layout:'fit',
title:'The Title',
xtype: 'tabpanel', // TabPanel itself has no title
activeTab: 0, // First tab active by default
items:
[{
xtype: 'userlist',
listeners:
{
select: function(selModel, record, index, options)
{
// do something with the selected date
// Ext.Msg.alert(record.data.message_id, record.data.recip_email +'<br> ' + record.data.unix_time_stamp);
}
}
}]
},
{
region: 'west',
layout:'fit',
xtype: 'tabpanel',
activetab:0,
collapsible:false,
split: false,
title: 'The Title',
width:178,
maxWidth:400,
height: 100,
minHeight: 100,
items:
[
{
title: 'Tab 1',
xtype:'panel',
items:
[{
xtype: 'datepicker',
minDate: new Date('12/15/2013'),
maxDate: new Date(),
// Disable dates is set to invert dates in array
disabledDates:["^(?!"+dateArray.join("|")+").*$"],
// disabledDates:["^("+dateArray.join("|")+").*$"],
handler: function(picker, date)
{
// do something with the selected date
// Ext.Msg.alert('date picker example in init2.js' + '<br>' + Ext.Date.format(date,'m/d/Y'));
console.log('date picker example in init2.js' + Ext.Date.format(date,'m/d/Y'));
// get store by unique storeId
var store = Ext.getStore('Users');
// clear current filters
store.clearFilter(true);
// filter store
store.filter("unix_time_stamp", Ext.Date.format(date,'m/d/Y'));
// store.proxy.extraParams = { key:'test'};
store.load();
}
}]
},
{
title: 'Tab 2',
html: 'ers may be added dynamically - Others may be added dynamically',
}
]
}
]
});
}
});
If you want to filter records displayed in grid by selected date in date picker on the server side try to filter grid's store.
In your store configuration you need to set remoteFilter config attribute to true. Then store proxy will automatically add filter params into store load data requests. Also if you have only one instance of this store, add to configuration unique storeId.
In your datepicker handler you need set store filter to selected date:
handler: function(picker, date)
{
// get store by unique storeId
var store = Ext.getStore('storeId');
// clear current filters
store.clearFilter(true);
// filter store
store.filter("unix_time_stamp", date);
}
Then on server side you need to parse and process filter param.

Resources