ExtJS is more verbose than jQuery, it makes you write more to do something compared to jQuery. I know that we should not compare jQuery with ExtJS but as ExtJS is a most complete Javascript UI framework while jQuery is library. But after working with jQuery for quite some time it looks like our productivity get reduced when we move to ExtJS.
var panel = Ext.create('Ext.panel.Panel',{
height: 500,
width: 500,
renderTo: Ext.getBody(),
...
Can't we save some keystrokes here? Same goes for creating a textbox in form and other components.
EDIT
#Verbose Code:
function createPanel(){
var panel = Ext.create('Ext.panel.Panel',{
height: 500,
width: 500,
renderTo: Ext.getBody(),
layout: {
type: 'vbox',
align: 'stretch'
},
items: [{
xtype: 'tabpanel',
itemId: 'mainTabPanel',
flex: 1,
items: [{
xtype: 'panel',
title: 'Users',
id: 'usersPanel',
layout: {
type: 'vbox',
align: 'stretch'
},
tbar: [{
xtype: 'button',
text: 'Edit',
itemId: 'editButton'
}],
items: [{
xtype: 'form',
border: 0,
items: [{
xtype: 'textfield',
fieldLabel: 'Name',
allowBlank: false
}, {
xtype: 'textfield',
fieldLabel: 'Email',
allowBlank: false
}],
buttons: [{
xtype: 'button',
text: 'Save',
action: 'saveUser'
}]
}, {
xtype: 'grid',
flex: 1,
border: 0,
columns: [{
header: 'Name',
dataIndex: 'Name',
flex: 1
}, {
header: 'Email',
dataIndex: 'Email'
}],
store: Ext.create('Ext.data.Store',{
fields: ['Name', 'Email'],
data: [{
Name: 'Indian One',
Email: 'one#qinfo.com'
}, {
Name: 'American One',
Email: 'aone#info.com'
}]
})
}]
}]
},{
xtype: 'component',
itemId: 'footerComponent',
html: 'Footer Information',
extraOptions: {
option1: 'test',
option2: 'test'
},
height: 40
}]
});
}
#Compact Code
// Main global object holding
var q = {
// config object templates
t: {
layout: function(args) {
args = args || {};
var o = {};
o.type = args.type || 'vbox';
o.align = args.align || 'stretch';
return o;
},
panel: function(args) {
args = args || {};
var o = {};
o.xtype = 'panel';
o.title = args.title || null;
o.id = args.id || null;
o.height = args.height || null;
o.width = args.width || null;
o.renderTo = args.renderTo || null;
o.tbar = args.tbar || null;
o.layout = args.layout || q.t.layout();
o.items = args.items || [];
return o;
},
button: function(text, args) {
args = args || {};
var o = {};
o.xtype = 'button';
o.text = text;
o.itemId = args.itemId;
return o;
},
tabPanel: function(args) {
args = args || {};
var o = {};
o.xtype = 'tabpanel';
o.itemId = args.itemId;
o.flex = args.flex;
o.layout = args.layout;
o.tbar = args.tbar;
o.items = args.items || [];
return o;
},
form: function(args) {
args = args || {};
var o = {};
o.xtype = 'form';
o.border = args.border || 0;
o.items = args.items || [];
o.buttons = args.buttons || [];
return o;
},
grid: function(args) {
args = args || {};
var o = {};
o.xtype = 'grid';
o.flex = args.flex || 1;
o.border = args.border || 0;
o.columns = args.columns || [];
o.store = args.store || null;
return o;
},
gColumn: function(header, dataIndex, args) {
args = args || {};
var o = {};
o.header = header;
o.dataIndex = dataIndex;
o.flex = args.flex || undefined;
return o;
},
fTextBox: function(label, optional, args) {
args = args || {};
var o = {};
o.xtype = 'textfield';
o.fieldLabel = label;
o.allowBlank = optional || true;
return o;
},
component: function(args) {
args = args || {};
var o = {};
o.xtype = 'component';
o.itemId = args.itemId;
o.html = args.html;
o.extraOptions = args.extraOptions;
return o;
}
},
// Helper methods for shortening Ext.create for containers.
h: {
panel: function(args) {
return Ext.create('Ext.panel.Panel',
args);
}
}
};
function createPanel(){
var panel = q.h.panel({
height: 500,
width: 500,
renderTo: Ext.getBody(),
layout: q.t.panel(),
items: [q.t.tabPanel({
itemId: 'mainTabPanel',
items: [q.t.panel({
title: 'Users',
id: 'usersPanel',
tbar: [
q.t.button('Edit',{itemId: 'editButton'})
],
items: [
q.t.form({
items: [ q.t.fTextBox('Name') , q.t.fTextBox('Email')],
buttons: [ q.t.button('Save', {action:'saveUser'} )]
}),
q.t.grid({
columns: [ q.t.gColumn('Name','name'), q.t.gColumn('Email', 'email', {flex: null}) ],
store: Ext.create('Ext.data.Store',{
fields: ['name', 'email'],
data: [{
name: 'Indian One',
email: 'one#qinfo.com'
}, {
name: 'American One',
email: 'aone#info.com'
}]
})
})]
})]
}),
q.t.component({
itemId: 'footerComponent',
html: 'Footer Information',
extraOptions: {
option1: 'test',
option2: 'test'
},
height: 40
})
]
});
}
By going with the #Compact code, it saves about 40% in terms of number of lines for example function here which is "createPanel". I wanted everyone to come up with different ideas and creating config object was one of my first idea but I wanted it to be something which I can override so I come up with above approach.
I did benchmark both the function and per Firebug (profiling feature) non-compact version takes 178ms while compact version takes 184ms.
So yes, it is going to take some more time for sure and it looks worth from this example with 8ms more but not sure when we will build an enterprise application with this approach.
Is there any better approach?, if yes please do share.
If not really needed use xtypes:
{
xtype: 'panel',
height: 500,
width: 500,
renderTo: Ext.getBody()
}
or create yourself default configs
var panelCfg = {
height: 500,
width: 500,
renderTo: Ext.getBody()
}
and apply the with ExtApplyIf
Ext.ApplyIf({xtype:'panel'}, panelCfg);
or to get a instance
Ext.widget('panel', panelCfg);
And there are still more ways.
You will definitive need to write yourself some struct and/or helpers which encapsulates your default configurations or even directly inherit your own classes from existing ones.
In addition from what sra said, nothing stops you from creating a few short-hand methods.
Using simple generating functions with extending/mixing configs helps quite a lot.
Related
I have some store, which is formed data. On panel it looks how "fieldName" and text field (in depension from invoked form). For example, on one form is displayed "name document" and field, on another: date of selling and date field. Data is formed dynamicly
Here is store:
tableTempStore = new Ext.data.JsonStore({
url: objectUrlAddress,
baseParams: {
'objectID': objectID
},
root: 'Fields',
fields: [{
name: 'Type',
type: 'int'
}, {
name: 'Value'
}, {
name: 'IsRequired',
type: 'bool'
}, {
name: 'Identifier'
}, {
name: 'Data'
}],
listeners: {
load: function(obj, records) {
Ext.each(records, function(rec) {
var item = null;
switch (rec.get('Type')) {
case 0:
item = new Ext.form.NumberField();
item.id = rec.get('Identifier');
item.fieldLabel = rec.get('Hint');
var isRequired = rec.get('IsRequired');
item.anchor = '100%';
item.allowBlank = !isRequired;
item.disabled = editDisabled;
item.value = rec.get('Data');
break;
case 1:
item = new Ext.form.NumberField();
item.id = rec.get('Identifier');
item.fieldLabel = rec.get('Hint');
var isRequired = rec.get('IsRequired');
item.anchor = '100%';
item.allowBlank = !isRequired;
item.allowDecimals = true;
item.disabled = editDisabled;
item.value = rec.get('Data');
break;
}
if (item != null) {
templateGrids.add(item);
columnsTable = item.__proto__.constructor.xtype;
source[item.fieldLabel] = '';
var s = null;
if (columnsTable == 'textfield')
{
s = 'textfield';
colm = {
xtype: s,
id: item.id,
allowBlank: item.allowBlank,
format: item.format,
value: item.value,
editable: true,
emptyText: item.emptyText,
disabled: item.disabled
};
}
else if (columnsTable == 'combo')
{
s = 'combo';
colm = {
xtype: s,
id: item.id,
allowBlank: item.allowBlank,
format: item.format,
value: item.value,
editable: true,
emptyText: item.emptyText,
disabled: item.disabled
};
}
else if (columnsTable == 'datefield')
{
s = 'datefield';
colm = {
xtype: s,
id: item.id,
allowBlank: item.allowBlank,
format: item.format,
value: item.value,
editable: true,
emptyText: item.emptyText,
disabled: item.disabled
};
}
});
for (var i = 0; i < templateGrids.getStore().data.length; i++) {
templateGrids.getColumnModel().setConfig([
{header: 'Name', id:'name', width:200},
{header:'Value', id:'val', dataIndex: rec.get('Value'), editable:true, width:200, editor: colm}]);
};
}
}
});
This code had worked in a form, but I need to use Grid (or Editor Grid). I know, how displayed field name ("document name" and etc.), but I don't understand, how displayed text field or etc. I try use loop, but on second column in xtype displayed last type in store. How i can resolve this problem?!
Here is a grid:
var templateGrids = new Ext.grid.EditorGridPanel({
id: 'tableId',
height:300,
width: '100%',
clicksToEdit:1,
frame: true,
store: tableTempStore,
columns: [
{header: 'Name'},
{header: 'Value'}]
});
I have some store, which is formed data. On panel, it looks how "fieldName" and text field (in depension from invoked form).
For example, on one form is displayed "name document" and field, on another: date of selling and date field. Data is formed dynamically.
Here is store:
tableTempStore = new Ext.data.JsonStore({
url: objectUrlAddress,
baseParams: {
'objectID': objectID
},
root: 'Fields',
fields: [{
name: 'Hint'
}, {
name: 'Type',
type: 'int'
}, {
name: 'Value'
}, {
name: 'Index',
type: 'int'
}, {
name: 'IsRequired',
type: 'bool'
}, {
name: 'Identifier'
}, {
name: 'EnumList'
}, {
name: 'Directory'
}, {
name: 'Data'
}],
listeners: {
load: function (obj, records) {
Ext.each(records, function (rec) {
var item = null;
switch (rec.get('Type')) {
case 0: // целое
item = new Ext.form.NumberField();
item.id = rec.get('Identifier');
item.fieldLabel = rec.get('Hint');
var isRequired = rec.get('IsRequired');
item.anchor = '100%';
item.allowBlank = !isRequired;
item.disabled = editDisabled;
item.value = rec.get('Data');
break;
case 1: // вещественное
item = new Ext.form.NumberField();
item.id = rec.get('Identifier');
item.fieldLabel = rec.get('Hint');
var isRequired = rec.get('IsRequired');
item.anchor = '100%';
item.allowBlank = !isRequired;
item.allowDecimals = true;
item.disabled = editDisabled;
item.value = rec.get('Data');
break;
case 5: // SQL-справочник
var dataValues = Ext.util.JSON.decode(rec.get('EnumList'));
var dataArray = Object.keys(dataValues).map(function (k) {
return [k, dataValues[k]]
});
item = new Ext.form.ComboBox({
typeAhead: true,
width: '100%',
triggerAction: 'all',
forceSelection: true,
editable: false,
hiddenName: rec.get('Identifier'),
mode: 'local',
store: new Ext.data.ArrayStore({
fields: [{
name: 'myId',
type: 'string'
}, {
name: 'displayText'
}],
data: dataArray
}),
valueField: 'myId',
displayField: 'displayText',
disabled: editDisabled
});
item.id = '_' + rec.get('Identifier');
item.anchor = '100%';
item.fieldLabel = rec.get('Hint');
var isRequired = rec.get('IsRequired');
item.allowBlank = !isRequired;
item.value = rec.get('Data');
break;
}
if (item != null) {
templateGrids.add(item);
columnsTable = item.__proto__.constructor.xtype;
var s = null;
else if (rec.get('Type') == 4) {
var dataValues = Ext.util.JSON.decode(rec.get('EnumList'));
var dataArray = Object.keys(dataValues).map(function (k) {
return [k, dataValues[k]]
});
combo = new Ext.grid.GridEditor(new Ext.form.ComboBox({
id: item.id,
allowBlank: item.allowBlank,
typeAhead: true,
lazyRender: true,
triggerAction: 'all',
forceSelection: true,
queryMode: 'local',
editable: false,
value: item.value,
hiddenName: rec.get('Identifier'),
mode: 'local',
store: new Ext.data.ArrayStore({
fields: [{
name: 'myId',
type: 'string'
}, {
name: 'displayText',
type: 'string'
}],
data: dataArray
}),
valueField: "myId",
displayField: "displayText",
disabled: editDisabled
}));
}
source[item.fieldLabel] = '';
grid.customEditors['Сохранить в'] = combo;
grid.getColumnModel().setConfig([{
header: "Поле"
}, {
header: "Значение",
dataIndex: '',
renderer: Ext.util.Format.comboRenderer(combo)
}]);
grid.setSource(source);
};
});
}
}
});
Here's my property grid:
grid = new Ext.grid.PropertyGrid({
url: objectUrlAddress,
id: 'propGrid',
autoFill: true,
autoHeight: true,
width: 200,
store: tableTempStore,
width: 600,
style: 'margin:0 auto;margin-top:10px;'
});
Problem with combo box. It show itemValue instead fieldValue on cell, and I don't know how to resolve this problem. How can I do? Thanks in advance.
For rendering I used function:
Ext.util.Format.comboRenderer = function (combo) {
return function (value) {
var record = combo.findRecord(combo.valueField, value);
return record ? record.get(combo.displayField) : combo.valueNotFoundText;
}
};
But it not worked.
I'm creating a new EXTJS window and inside that window there is a panel and inside that panel there is a form!
When I click on the 'X' or cancel to close the window I get this error:
Uncaught TypeError: Cannot read property 'className' of undefinedhasClass
# ext-all-debug.js:2252addClass
# ext-all-debug.js:2183Ext.Button.Ext.extend.onMouseOver
# ext-all-debug.js:31140aK
# miframe.js:1
I am using this handler in the cancel button:
handler: function () {
this.close();
},
Full code -
example.SurveyFieldDefaultWindow = Ext.extend(Ext.Window, {
id: 'survey-default-win',
title: 'Custom Survvey',
modal: true,
closable: true,
width: 500,
height: 600,
frame: true,
bodyStyle: 'padding: 5px',
forceFit: true,
constrainHeader: true,
layout: 'fit',
initComponent: function () {
this.canEdit = this.checkEditPermissions();
questionStore2 = questionStore;
var survey_window = Ext.getCmp('survey-win');
survey_window.afterRender(
survey_window.getFormValues()
);
formValues2 = formValuesObj;
survey_default_id = Math.floor(10000 + Math.random() * 90000);
Ext.apply(
this, {
items: [{
xtype: 'tabpanel',
id: 'survey-field-form-tabpanel',
layoutOnTabChange: true,
activeTab: 0,
items: [{
title: 'Questions',
layout: 'fit',
items: [{
xtype: 'form',
id: 'survey-field-form',
border: false,
bodyStyle: 'padding: 5px;',
frame: true,
defaultType: 'textfield',
}]
}]
}],
buttons: [{
id: 'save-button',
text: 'Default-Save',
handler: function () {
this.saveForm()
},
scope: this
}, {
text: 'Default-Cancel',
handler: function () {
this.close();
},
scope: this
}]
}
);
example.SurveyFieldDefaultWindow.superclass.initComponent.apply(this, arguments);
var data = questionStore2.data.items;
for (var i = 0; i < data.length; i++) {
if (data[i].data.fieldTypeName == "DropDownList" || data[i].data.fieldTypeName == "RadioButtonList" || data[i].data.fieldTypeName == "CheckBoxList" || data[i].data.fieldTypeName == "Rating" || data[i].data.fieldTypeName == "YesNo") {
// create a Record constructor:
var rt = Ext.data.Record.create([
{name: 'optionValue'},
{name: 'optionText'}
]);
var myStore = new Ext.data.Store({
// explicitly create reader
reader: new Ext.data.ArrayReader(
{
idIndex: 0 // id for each record will be the first element
},
rt // recordType
)
});
var myData = [];
for (var j = 0; j < data[i].data.selectOptions.list.length; j++) {
var optionText = data[i].data.selectOptions.list[j].optionText.toString();
var optionValue = data[i].data.selectOptions.list[j].optionValue.toString();
myData.push([optionValue, optionText]);
}
myStore.loadData(myData);
var id = data[i].data.name.toString();
var cb = new Ext.form.ComboBox({
fieldLabel: data[i].data.name,
id: id,
typeAhead: true,
allowBlank: true,
mode: 'local',
emptyText: 'Select Default value',
width: 190,
margin: '40 30 20 10',
store: myStore,
valueField: 'optionValue',
displayField: 'optionText',
selectOnFocus: true,
triggerAction: 'all',
listeners: {
'select': function (cb, newValue, oldValue) {
for (var i = 0; i < formValues2.fields.list.length; i++)
{
for (var j = 0; j < formValues2.fields.list[i].selectOptions.list.length; j++)
{
if(formValues2.fields.list[i].name == cb.fieldLabel ){
if( formValues2.fields.list[i].selectOptions.list[j].optionText == cb.lastSelectionText) {
formValues2.fields.list[i].selectOptions.list[j].preselect = true;
}
}
}
}
}
}
});
Ext.getCmp('survey-field-form').add(cb);
Ext.getCmp('survey-field-form').doLayout();
}
}
getDefaultSurveyFormValues = Ext.getCmp('survey-field-form');
getDefaultSurveyFormValues.on("afterrender", function () {
//this code will run after the panel renders.
if (getDefaultSurveyFormValues != undefined) {
getDefaultSurveyFormValues.getForm().getValues();
}
else {
console.log('undefined getDefaultSurveyFormValues');
}
});
},
checkEditPermissions: function () {
return Security.hasAccess("Surveys", Security.UPDATE_ACCESS);
},
saveForm: function () {
// disable save button while saving form
// Ext.getCmp('save-button').disable(); ----------------------------------- undo comment later
// submit the form using a jabsorb call
Ext.getCmp('survey-field-form').getForm().doAction("JabsorbSubmit", {
formValues: formValues2,
jabsorbMethod: Jabsorb.getInstance().surveyTemplateService.saveSurveyTemplate,
// timeout:300000,
failure: function (form, action) {
Ext.Msg.alert('Request Failed', 'Could not save survey template information to generate Survey View: ' + action.result.msg);
},
success: function (form, action) {
Ext.Msg.alert('magic' , 'magic');
}
});
}
});
Ext.reg('example.SurveyFieldDefaultWindow', example.SurveyFieldDefaultWindow);
I've made a fiddle, based on your code to create the window and using the close button. Check it here: https://fiddle.sencha.com/#fiddle/16lu
From what i've seen, in your initComponent: function() { you never call the this.callParent() method. It's very important for class inheritance if you use the initComponent config.
From the docs:
Call the "parent" method of the current method. That is the method
previously overridden by derivation or by an override (see
Ext.define).
In this scope, this represent the button and not the window, so you trying to close the button
Im using a jqGrid:
colModel: [
{ name: 'IdTarifaAcceso', index: 'IdTarifaAcceso', hidden: true },
{ name: 'TipoTension.IdTipoTension', index: 'TipoTension.IdTipoTension' , hidden: true},
{ name: 'DsTarifaAcceso', index: 'DsTarifaAcceso', width: (pageWidth * (9.9 / 100)), stype: 'text', align: "center" },
{ name: 'TipoTension.DsTipoTension', index: 'IdTarifaAcceso', hidden: true }
],
beforeSelectRow: function (rowid, e) {
var $self = $(this),
iCol = $.jgrid.getCellIndex($(e.target).closest("td")[0]),
cm = $self.jqGrid("getGridParam", "colModel");
var rowData = $(this).jqGrid('getRowData', rowid);
When I want get the value of TipoTension.DsTipoTension in the beforeSelectRow section, I get the error of null reference:
var = rowData.TipoTension.IdTipoTension;
}
Any idea?
Thanks!
my issue is that I want to update existing store and show the changes on the grid.
What I'm doing to update is :
var record = store.getById(me.internalParameters.editInfo.id);
//console.log(me.InfoEditorPanel.hardwareIdField.value);
record.set('hardwareid', me.InfoEditorPanel.hardwareIdField.value);
record.set('location', me.InfoEditorPanel.locationField.value);
record.set('isActive', me.InfoEditorPanel.isActiveField.value);
record.commit();
store.load();
Here what I use to build the grid.
Utils.getPanelListGrid = function (parameters) {
if (parameters.initParameters == null)
parameters.initParameters = {};
var initParameters = parameters.initParameters;
initParameters.gridColumns = [
{ header: "ID", dataIndex: "id", flex: 1 },
{ header: "Hardware ID", dataIndex: "hardwareid", flex: 1 },
{ header: "Location", dataIndex: "location", flex: 1 },
{ header: "Active", dataIndex: "isActive", flex: 1 }
];
return new Backend.shared.MyDataGrid(parameters);
};
Ext.define(
"shared.MyDataGrid", {
extend: "Ext.grid.Panel",
xtype: "MyDataGrid",
title: "MyDataGrid - Hardcoded values",
initParameters: {
storeIdProperty: null,
},
initComponent: function () {
this.store = Ext.create('Ext.data.Store', {
storeId: 'myStore',
proxy: {
type: 'memory',
reader: {
type: 'json',
root: 'items'
}
},
fields: ['id', 'hardwareid', 'location', 'isActive'],
data: {
'items': [{
'id': '123456',
'hardwareid': "HID-159",
'location': "Bedroom",
'isActive': "No"
}, {
'id': '789456',
'hardwareid': "HID-357",
'location': "Kitchen",
'isActive': "Yes"
}, {
'id': '147852',
'hardwareid': "HID-149",
'location': "Guest-room",
'isActive': "Yes"
}
]
}
});
this.columns = this.initParameters.gridColumns;
this.listeners = {
selectionchange: {
scope: this,
fn: function (selectionModel, selectedRecords, eventOptions) {
this.selectedIds = [];
this.selectedItems = [];
if (selectedRecords != null) {
for (var i = 0; i < selectedRecords.length; i++) {
var item = selectedRecords[i].data;
this.selectedIds.push(item[this.initParameters.storeIdProperty]);
this.selectedItems.push(item)
}
}
if (this.initParameters.selectionChangeCallback != null)
this.initParameters.selectionChangeCallback(this.selectedIds, this.selectedItems);
}
}
};
shared.MyDataGrid.superclass.initComponent.call(this);
},
getRecordCount: function () {
return this.getStore().getTotalCount();
},
getSelectedIds: function () {
return this.selectedIds;
},
getSelectedItems: function () {
return this.selectedItems;
}
});
Can anyone please explain what should I do exactly to make the grid show the updated row?
I suggest that use the following code in your 'selectionchange' event.
this.getStore().load({
params:{
'yourModelIdProperty':'selectedId'
}
});
It's call an store proxy. You should write a function for that proxy and load the updated data.