How can I add a function inside the tpl field that belongs to the itemConfig object in an Extjs grid? - extjs

I have an ExtJs grid with the expander plugin. (Note that I use Sencha Architect 4.2.9 and ExtJs 7.3.3 Modern)
As I understand it, the only way I can add an Ext.template for the rows of the expander plugin is by writing it inside the itemConfig object of the grid.
xtype: 'grid',
id: 'mygrid1',
itemId: 'mygrid1',
name: 'MyGrid1',
store: 'stTasks',
itemConfig: {
xtype: 'gridrow',
body: {
tpl: '<div>{title}</div>',
}
},
plugins: [
{
type: 'rowexpander'
}
],
How can I add a function to that tpl? All solutions I have found don't work as they are geared towards the creation of new Ext.Template objects, and not for tpl strings inside an object.
For example, the following code doesn't work:
itemConfig: {
xtype: 'gridrow',
body: {
tpl: '<div> {[this.getResults()]} </div>',
getResults: function() {
return 'results';
}
}
},
Warning message:
[W] XTemplate evaluation exception: this.getResults is not a function
I have tried putting the function object anywhere that makes sense, but I can not call it from inside the tpl no matter how I write it.
It seems like such a trivial task, but I'm scratching my head over this for 3 days now.

You must specify those functions in the context of the XTemplate, so instead if string templates create a new Ext.XTemplate instance earlier, where you have control of template context, for example:
Ext.application({
name: 'Fiddle',
launch: function () {
Ext.Viewport.add({
xtype: 'grid',
id: 'mygrid1',
itemId: 'mygrid1',
name: 'MyGrid1',
store: 'stTasks',
columns: [{
name: 'value',
dataIndex: 'value'
}],
data: [{
value: 'a'
}, {
value: 'b'
}],
itemConfig: {
xtype: 'gridrow',
body: {
tpl: new Ext.XTemplate('<div> {[this.getResults()]} </div>', {
getResults: function () {
return 'results';
}
})
}
},
plugins: [{
type: 'rowexpander'
}],
});
}
});

Ok, found a solution.
Posting it here for future reference to anyone that encounters the same problem.
It turns out I had to set the "tpl" as an array, with the first element being the template string, and the second element being an object containing the function
itemConfig: {
xtype: 'gridrow',
body: {
tpl: [
'<div> {[this.getResults()]} </div>', {
getResults: function() {
return 'results';
}
}
]
}
},

Related

ExtJS - unable to bind column header

I have an ExtJS 6.5.1 app. I am unable to bind a grid column to the viewModel. I am using the same viewModel for a grid && a form.
If I bind the fieldLabel it works. If I bind the grid title to that viewModel that also works. Its just the column header I am unable to bind.
I get the following errors:
Ext.mixin.Bindable.applyBind(): Cannot bind header on Ext.grid.column.Column - missing a setHeader method.
And
this[binding._config.names.set] is not a function
Someone elsewhere was getting similiar errors for development mode because some required classes weren't loading so he was able to resolve it by requiring Ext.data.proxy.*. I tried the same and just "*" but got the same erorrs.
Here is the FIDDLE.
The header config deprecated since version 4.0 use text instead.
Paste bellow code in your FIDDLE it will work and bind perfectly.
CODE SNIPPET
Ext.define('MyApp.view.TestViewModel', {
extend: 'Ext.app.ViewModel',
alias: 'viewmodel.test',
data: {
title: ''
},
constructor: function (config) {
var me = this;
this.callParent(arguments);
me.setStores({
lang: {
fields: ['title'],
proxy: {
type: 'ajax',
url: 'data.json',
reader: {
type: 'json'
}
},
autoLoad: true,
listeners: {
load: function (store, records) {
me.set('title', store.getAt(0).get('title'));
}
}
}
});
}
});
Ext.define('MyApp.view.TestGrid', {
extend: 'Ext.grid.Panel',
title: "MY GRID",
xtype: "mygrid",
viewModel: {
type: 'test'
},
columns: [{
text: "Col1"
}, {
bind: {
text: "{title}"
},
flex: 1
}]
});
Ext.define('MyApp.view.TestForm', {
extend: 'Ext.form.Panel',
layout: 'fit',
title: "MY FORM",
xtype: "myform",
viewModel: {
type: 'test'
},
items: [{
xtype: "textfield",
bind: {
fieldLabel: "{title}"
}
}]
});
Ext.onReady(function () {
Ext.create('Ext.container.Container', {
renderTo: Ext.getBody(),
layout: "fit",
flex: 1,
items: [{
xtype: "myform"
}, {
xtype: "mygrid"
}]
});
});

Extjs6.2 Modern toolkit- Extend a textbox

I am still learning EXTJs and one of the thing I was trying to to was extend a component. Below is my example:
Ext.define('MyApp.view.CustomTextField',{
extend: 'Ext.field.Text',
xtype: 'customtextfield',
config:
{
fieldID: null,
langID: null
},
initialize: function() {
alert("init"); //1. called before I navigate to view
Call a controller method here
this.callParent(arguments);
},
initComponent: function () {
alert("initComp"); //2. not called at all
Call a controller method here
this.callParent(arguments);
}
I want to call a controller method to validate if user has permission to see this field and accordingly do next actions. I want this validation to happen when I navigate to the view
I used this custom field in my View as:
xtype: 'fieldset',
margin: 10,
bind: '{workOrders}',
title: 'Dispatch Information',
items: [
{
id: 'Tag',
xtype: 'customtextfield',
name: 'Tag',
label: 'Tag',
bind: '{Tag}',
labelAlign: 'top'
},
But the initComponent is never fired.
The initialize is fired to soon ,even before my stores are loaded. How do I properly extend this control?
In ExtJS 6 modern there is no initComponent event for textfield . initComponent event have
in classic for textfield.
For calling events in controller you need to create controller and define to you view.
In this FIDDLE, I have created a demo using form, ViewController, textfield and ViewModel. I hope this will help/guide you to achieve your requirements.
For more details please refer ExtJS Docs.
CODE SNIPPET
Ext.application({
name: 'Fiddle',
launch: function () {
//Define the cutsometext from extending {Ext.field.Text}
Ext.define('CustomText', {
extend: 'Ext.field.Text',
xtype: 'customtext',
labelAlign: 'top',
listeners: {
initialize: 'onInitializeCutsomText'
}
});
Ext.define('FormModel', {
extend: 'Ext.app.ViewModel',
alias: 'viewmodel.formmodel',
data: {
user: {
firstName: 'Narendra',
lastName: 'Jadhav',
email: 'narendrajadhav105#gmail.com'
},
permissionCng: {
firstName: false,
lastName: false,
email: true,
isAdmin: false
}
}
});
//Define the FormController from extending {Ext.app.ViewController}
Ext.define('FormController', {
extend: 'Ext.app.ViewController',
alias: 'controller.formctn',
onInitializeCutsomText: function (textfield) {
var permissionCng = this.getViewModel().get('permissionCng');
// Here is just basic example for disabled textfield on initialize event.
//In your case you can put your requirement.
textfield.setDisabled(permissionCng[textfield.getName()]);
}
});
//Creating form
Ext.create('Ext.form.Panel', {
fullscreen: true,
viewModel: {
type: 'formmodel'
},
controller: 'formctn',
items: [{
xtype: 'fieldset',
title: 'Personal Info',
defaults: {
xtype: 'customtext' //Here I am using {customtext}
},
items: [{
label: 'First Name',
name: 'firstName',
bind: {
value: '{user.firstName}',
//You can also use like property
//hidden:'{permissionCng.firstName}'
}
}, {
label: 'Last Name',
name: 'lastName',
bind: {
value: '{user.lastName}',
//You can also use like property
//hidden:'{permissionCng.firstName}'
}
}, {
label: 'Email Id',
name: 'email',
bind: {
value: '{user.email}',
//You can also use like property
//hidden:'{permissionCng.firstName}'
}
}, {
label: 'Admin Name',
name: 'isAdmin',
bind: {
value: '{user.isAdmin}',
//You can also use like property
hidden: '{!permissionCng.isAdmin}'
}
}]
}]
});
}
});

ExtJS 5.1: Binding record value to component property

Let's say I've got a ViewController, ViewModel, and my View. In the View, I've got a form panel that gets a loaded record. When this record loads into the form, I want to hide or show a button based on the record's status field, so I figured do something with binding. However, it looks like binding is limited to only inverting, not actually using an expression. To get a better understanding, take a look at this code:
Ext.application({
name : 'Fiddle',
launch : function() {
Ext.define('User', {
extend: 'Ext.data.Model',
fields: ['name', 'status']
});
Ext.define('UserListController', {
extend : 'Ext.app.ViewController',
alias: 'controller.userlist'
});
Ext.define('UserListViewModel', {
extend: 'Ext.app.ViewModel',
alias: 'viewmodel.userlist'
});
Ext.define('UserList', {
extend: 'Ext.form.Panel',
controller: 'userlist',
viewModel: 'userlist',
tbar: [{
text: 'Add',
reference: 'addButton',
bind: {
//hidden: '{status == 2}'
}
}, {
text: 'Delete',
reference: 'deleteButton',
bind: {
//hidden: '{status == 1}'
}
}],
items: [{
xtype: 'displayfield',
name: 'name',
fieldLabel: 'Name'
}, {
xtype: 'displayfield',
name: 'status',
fieldLabel: 'Status'
}]
});
var myForm = Ext.create('UserList', {
width: 400,
height: 200,
renderTo: Ext.getBody()
});
var record = Ext.create('User', {
name: 'blah',
status: 2
});
myForm.loadRecord(record);
if (record.get('status') === 2) {
myForm.lookupReference('addButton').hide();
}
}
});
As you can see, I'm currently just probing the values of the record to hide the addButton. Is there anyway I can accomplish this with binding or some other approach? It's good to note that I also looked at formulas, but from what I'm understanding, that's only for changing how data is rendered, so it didn't seem like the proper route.
If your record is part of the view model data - use formulas, like:
formulas: {
hideDeleteButton: function (getter) {
return getter('record.status') === 2;
},
hideAddButton: function (getter) {
return getter('record.status') === 1;
}
}
And then in your view you can bind:
{
text: 'Add',
reference: 'addButton',
bind: {
hidden: '{hideAddButton}'
}
}, {
text: 'Delete',
reference: 'deleteButton',
bind: {
hidden: '{hideDeleteButton}'
}
}
A working example: https://fiddle.sencha.com/#fiddle/mcg

Rally API 2 inspect contents of a model

I have some code that is pulling a Release model back and displaying in a grid, this is working fine, but I cannot work out how to inspect what is in the returned model.
What I would like is to get the contents of the model in some kind of object that I can reorganise or drill into as I see fit (in this case the release model).
If I add a component and just dump the model into the html it is not returning the contents as I would expect.
Rally.data.ModelFactory.getModel({
type: 'Release',
success: function(model) {
this.add({
xtype: 'component',
html: model
});
this.grid = this.add({
xtype: 'rallygrid',
model: model,
columnCfgs: [
'FormattedID',
'Name',
'RevisionHistory' ],
storeConfig: {
filters: queryFilters
}
});
},
scope: this
});
If I dig into the ExtJS docs it seems I should be able to do something like getData() on the model to return the contents but this is not working.
Inspection in the debugger tells me I have a "Rally.domain.v2.0.project.10098485624.Release" object but I can't see how to simply access the list of items in the object. Obviously there is a way because passing this model to a grid component will display it quite happily.
The debugger for this object shows me a number of further functions to call but I have no idea which one or how to use it
...
getArtifactMappings: function () {
getCollectionFields: function () {
getCustomFields: function () {
getField: function (fieldName) {
getFields: function () {
getFieldsByName: function (fieldNames) {
getName: function () {
getNonCollectionFields: function () {
getPermissionLevels: function (permission) {
getProxy: function () {
etc...
The Rally docs indicate I should be able to call getData() on a model https://help.rallydev.com/apps/2.0rc2/doc/#!/api/Rally.data.Model but it looks like the ModelFactory.getModel() is not returning a type that has a getData() method
A model is a class, and a record is an instance of that class.
getData() will work on a record.
There are static methods that would work on the actual model, but getData() is not one of them.
Here is a fragment from the code below:
_onDataLoaded: function(store, data){
_.each(data, function(record){
var r = record.getData();
console.log('release', r);
This code builds a grid of Releases filtered by project and ReleaseStartDate. I noticed that in your code you want to display model information, maybe for debug purposes, by actually modifying the dom. I would prefer to use console.log, but in the example below I did both. I used a border layout with a footer, and set html proprety of the container in the footer to JSON.stringify(r)
Ext.define('CustomApp', {
extend: 'Rally.app.App',
componentCls: 'app',
layout:'border',
defaults: {
collapsible: true,
split: true,
bodyStyle: 'padding:15px',
},
items: [{
title: 'data',
region:'south',
itemId: 'd',
margins: '5 0 0 0',
cmargins: '5 5 0 0'
},{
title: 'Releases',
itemId: 'r',
collapsible: false,
region:'center',
margins: '5 0 0 0'
}] ,
launch: function() {
var context = this.getContext();
var projectId = context.getProject().ObjectID;
var millisecondsInDay = 86400000;
var currentDate = new Date();
var startDate = new Date(currentDate - millisecondsInDay*90); //in the last 90 days
var startDateUTC = startDate.toISOString();
Ext.create('Rally.data.WsapiDataStore', {
model: 'Release',
fetch: ['Name','ReleaseStartDate','ReleaseDate', 'State'],
filters: [
{
property: 'ReleaseStartDate',
operator: '>',
value: startDateUTC
},
{
property: 'Project',
operator: '=',
value: '/project/'+ projectId
}
],
autoLoad: true,
listeners: {
load: this._onDataLoaded,
scope: this
}
});
},
_onDataLoaded: function(store, data){
var text = '';
_.each(data, function(record){
var r = record.getData();
console.log('release', r);
text = text + JSON.stringify(r);
});
console.log('text', text);
this.down('#d').add({
xtype:'container',
html: text
});
if (!this.down('#g')) {
this.down('#r').add({
xtype: 'rallygrid',
store: store,
itemId: 'g',
columnCfgs: [
{
text: 'Name', dataIndex: 'Name'
},
{
text: 'State', dataIndex: 'State'
},
{
text: 'Start Date', dataIndex: 'ReleaseStartDate', flex:1
},
{
text: 'Release Date', dataIndex: 'ReleaseDate',flex:1
}
]
});
}
else{
(this.down('#g')).reconfigure(store);
}
}
});

sencha touch create tabs from store data

I am new to Senscha Touch and I have been struggling with this for hours.
I am trying to create an application where the main page has 1-3 tabs where title and content(html5) depends on json data.
My model has two fields: "title" and "text".
My store has dummy data for 2 tabs:
Ext.define('***', {
extend: 'Ext.data.Store',
config: {
model: '***',
xtype: 'informationTabs',
data: [
{
title: 'Museum',
text: 'Random html5'
},
{
title: 'Museum_2',
text: 'Random html5_2'
},
{
title: 'Museum_3',
text: 'Random html5_2'
}
]
}
})
To show it as a list i have the following code:
Ext.define('***', {
extend: 'Ext.Panel',
xtype: 'informationsTabs',
config: {
title: 'InformationTabs',
layout: 'fit',
items: [
{
xtype: 'list',
store: 'InformationTabs',
itemTpl: '{title}, {text}'
}
]
}
});
How do I get that to instead of making a list with two items, create two tabs with their title and text inside?
So in this case i should have two tabs.
Tab 1: Title = "title_1", content = "random_html5"
Tab 2: Title = "title_2", content = "random_html5_2"
Update:
With the following code (thanks kevhender!) it "works", except i get an extra "[object Object]" as the first tab. This option is also the only one with blue background when you click that tab.
Also this.callParent(); gets "Unresolved function or method".
Ext.define('***', {
extend: 'Ext.TabPanel',
xtype: 'informationsTabs',
config: {
title: 'informationsTabs',
items: [
{
xtype: 'tabbar',
store: 'InformationTabs',
title: '',
html: ['']
}
]
},
initialize: function() {
var items = [];
Ext.getStore('InformationTabs').each(function(rec) {
items.push({
title: rec.get('title'),
html: rec.get('text')
});
});
this.setItems(items);
this.callParent();
} });
screenshot: http://oi41.tinypic.com/2gsn53p.jpg
Since the store is dynamic, you won't be able to do the full definition in your static config block. You could put the tab creation into the initialize method, something like this:
Ext.define('***', {
extend: 'Ext.tab.Panel',
xtype: 'informationsTabs',
config: {
title: 'InformationTabs',
layout: 'fit',
items: [
{
xtype: 'list',
store: 'InformationTabs',
itemTpl: '{title}, {text}'
}
]
},
initialize: function() {
var items = [];
Ext.getStore('InformationTabs').each(function(rec) {
items.push({
title: rec.get('title'),
html: rec.get('text')
});
});
this.setItems(items);
this.callParent();
}
});

Resources