ExtJS: How to utilize UTC time in custom DateTimeField - javascript
I am trying to convert UTC timestamps to UTC Dates, modify those dates, and return the UTC timestamp of the selected date/time. Since the Ext.form.field.Date and Ext.form.field.Time fields use local time internally, I have to add 5 hours to the time and make sure the date stays the same, to retrieve the timestamp, I have to reverse the process and get the ISO timestamp (without milliseconds).
Everything seems to work OK, but when I select 2015-01-01T01:15:00Z the date field is set to the following day (01/02/2015; See Figure #1). I am not sure where I am failing to convert the date correctly?
Figure #1: Date is set to next day.
Edit
After fiddling around a bit, It looks like I got the date correct, but now the time field complains (See Figure #2). Looks like the value that was set is removed from the time drop-down. This is extremely confusing.
setValue: function (value) {
// ...
if (value != null && Ext.isDate(value)) {
var timeDate = Ext.clone(value);
timeDate.setFullYear(1970, 0, 1);
me.lookupReference('dateField').setValue(
Ext.Date.add(value, Ext.Date.MILLI, timeDate.getTime()));
me.lookupReference('timeField').setValue(me.convertFromUTC(timeDate));
}
// ...
}
Figure #2: Time field validation fails.
You can access a demo of the following code at the following sites:
JSFiddle
SenchaFiddle
DateTime.components.DateTimeField
Ext.define('DateTime.components.DateTimeField', {
extend: 'Ext.container.Container',
mixins: ['Ext.form.field.Field'],
alias: 'widget.datetimefield',
config: {
dateConfig: {},
timeConfig: {},
utcValue: true,
hideDate: false
},
referenceHolder: true,
layout: {
type: 'hbox'
},
initComponent: function () {
var me = this,
today = new Date(),
dateConfig = me.dateConfig,
timeConfig = me.timeConfig;
me.items = [Ext.apply({
xtype: 'datefield',
reference: 'dateField',
fieldLabel: 'Date',
value: today,
ignoreOnSubmit: true,
listeners: {
change: function (field, newValue, oldValue) {
me.fireEvent('dateFieldChange', field, newValue, oldValue);
}
}
}, dateConfig),
Ext.apply({
xtype: 'timefield',
reference: 'timeField',
format: 'H:i',
value: '00:00',
minValue: '00:00',
maxValue: '24:00',
increment: 15,
padding: '0 0 0 10',
width: 80,
ignoreOnSubmit: true
}, timeConfig)];
me.callParent();
},
afterRender: function () {
var me = this;
if (me.hideData) {
me.lookupReference('dateField').hide();
}
me.callParent();
},
getValue: function () {
var me = this,
dateValue = me.getDate(),
timeValue = me.getTime();
if (dateValue != null && timeValue != null) {
dateValue = Ext.Date.add(dateValue, Ext.Date.MILLI, timeValue);
}
return this.convertToUTC(dateValue);
},
setValue: function (value) {
var me = this;
if (value == null) {
return;
}
if (Ext.isString(value)) {
value = Ext.Date.parse(value, 'c');
}
// Debug
console.log('Parsed Date: ' + value);
if (value != null && Ext.isDate(value)) {
var timeDate = Ext.clone(value);
timeDate.setFullYear(1970, 0, 1);
timeDate = me.convertFromUTC(timeDate);
me.lookupReference('dateField').setValue(
Ext.Date.add(value, Ext.Date.MILLI, timeDate.getTime()));
me.lookupReference('timeField').setValue(timeDate);
}
},
getInputId: function () {
return null;
},
getTime: function () {
var me = this,
timeValue = me.lookupReference('timeField').getValue();
timeValue.setFullYear(1970, 0, 1);
timeValue = this.convertToUTC(timeValue, this.getDate());
return timeValue.getTime();
},
getDate: function () {
return this.lookupReference('dateField').getValue();
},
setDate: function (value) {
this.lookupReference('dateField').setValue(value);
},
convertToUTC: function (date, dateOffset) {
if (dateOffset == null) {
dateOffset = date;
}
if (this.utcValue) {
return Ext.Date.subtract(date, Ext.Date.MINUTE, dateOffset.getTimezoneOffset());
}
return date;
},
convertFromUTC: function (date, dateOffset) {
if (dateOffset == null) {
dateOffset = date;
}
if (this.utcValue) {
return Ext.Date.add(date, Ext.Date.MINUTE, dateOffset.getTimezoneOffset());
}
return date;
}
});
Full Code
//////////////////////////////////////////////////////////
// Requires
//////////////////////////////////////////////////////////
Ext.require(['*']);
//////////////////////////////////////////////////////////
// Data
//////////////////////////////////////////////////////////
var timestampData = [
['2014-02-28T08:45:00Z'],
['2015-01-01T01:15:00Z'],
['2014-12-31T11:30:00Z']
];
//////////////////////////////////////////////////////////
// Models
//////////////////////////////////////////////////////////
Ext.define('DateTime.model.Timestamp', {
extend: 'Ext.data.Model',
fields: ['timestamp']
});
//////////////////////////////////////////////////////////
// Stores
//////////////////////////////////////////////////////////
Ext.define('DateTime.store.Timestamp', {
extend : 'Ext.data.ArrayStore',
model: 'DateTime.model.Timestamp',
autoLoad: true,
autoSync: true,
proxy: {
type: 'memory'
}
});
//////////////////////////////////////////////////////////
// Mixins
//////////////////////////////////////////////////////////
Ext.define('DateTime.mixin.CommonUtils', {
dateToISOString: function (date) {
var pad = function (number) {
return ('00' + number).slice(-2);
};
return date.getUTCFullYear() + '-'
+ pad(date.getUTCMonth() + 1) + '-'
+ pad(date.getUTCDate()) + 'T'
+ pad(date.getUTCHours()) + ':'
+ pad(date.getUTCMinutes()) + ':'
+ pad(date.getUTCSeconds()) + 'Z';
}
});
//////////////////////////////////////////////////////////
// Components
//////////////////////////////////////////////////////////
Ext.define('DateTime.components.DateTimeField', {
extend: 'Ext.container.Container',
mixins: ['Ext.form.field.Field'],
alias: 'widget.datetimefield',
config: {
dateConfig: {},
timeConfig: {},
utcValue: true,
hideDate: false
},
referenceHolder: true,
layout: {
type: 'hbox'
},
initComponent: function () {
var me = this,
today = new Date(),
dateConfig = me.dateConfig,
timeConfig = me.timeConfig;
me.items = [Ext.apply({
xtype: 'datefield',
reference: 'dateField',
fieldLabel: 'Date',
value: today,
ignoreOnSubmit: true,
listeners: {
change: function (field, newValue, oldValue) {
me.fireEvent('dateFieldChange', field, newValue, oldValue);
}
}
}, dateConfig),
Ext.apply({
xtype: 'timefield',
reference: 'timeField',
format: 'H:i',
value: '00:00',
minValue: '00:00',
maxValue: '24:00',
increment: 15,
padding: '0 0 0 10',
width: 80,
ignoreOnSubmit: true
}, timeConfig)];
me.callParent();
},
afterRender: function () {
var me = this;
if (me.hideData) {
me.lookupReference('dateField').hide();
}
me.callParent();
},
getValue: function () {
var me = this,
dateValue = me.getDate(),
timeValue = me.getTime();
if (dateValue != null && timeValue != null) {
dateValue = Ext.Date.add(dateValue, Ext.Date.MILLI, timeValue);
}
return this.convertToUTC(dateValue);
},
setValue: function (value) {
var me = this;
if (value == null) {
return;
}
if (Ext.isString(value)) {
value = Ext.Date.parse(value, 'c');
}
// Debug
console.log('Parsed Date: ' + value);
if (value != null && Ext.isDate(value)) {
var timeDate = Ext.clone(value);
timeDate.setFullYear(1970, 0, 1);
timeDate = me.convertFromUTC(timeDate);
me.lookupReference('dateField').setValue(
Ext.Date.add(value, Ext.Date.MILLI, timeDate.getTime()));
me.lookupReference('timeField').setValue(timeDate);
}
},
getInputId: function () {
return null;
},
getTime: function () {
var me = this,
timeValue = me.lookupReference('timeField').getValue();
timeValue.setFullYear(1970, 0, 1);
timeValue = this.convertToUTC(timeValue, this.getDate());
return timeValue.getTime();
},
getDate: function () {
return this.lookupReference('dateField').getValue();
},
setDate: function (value) {
this.lookupReference('dateField').setValue(value);
},
convertToUTC: function (date, dateOffset) {
if (dateOffset == null) {
dateOffset = date;
}
if (this.utcValue) {
return Ext.Date.subtract(date, Ext.Date.MINUTE, dateOffset.getTimezoneOffset());
}
return date;
},
convertFromUTC: function (date, dateOffset) {
if (dateOffset == null) {
dateOffset = date;
}
if (this.utcValue) {
return Ext.Date.add(date, Ext.Date.MINUTE, dateOffset.getTimezoneOffset());
}
return date;
}
});
//////////////////////////////////////////////////////////
// Views
//////////////////////////////////////////////////////////
Ext.define('DateTime.view.MainView', {
extend: 'Ext.panel.Panel',
xtype: 'mainView',
alias: 'widget.mainview',
mixins: {
utils: 'DateTime.mixin.CommonUtils'
},
title: 'Date-Time Field Example',
referenceHolder: true,
layout: {
type: 'border',
//padding: 5
},
initComponent: function () {
var me = this;
me.items = [{
region: 'north',
xtype: 'grid',
itemId: 'timestampList',
store: Ext.create('DateTime.store.Timestamp', {
data : timestampData
}),
cls: 'timestamp-list',
multiSelect: false,
hideHeaders : true,
viewConfig: {
emptyText: 'No images to display'
},
columns: [{
dataIndex: 'timestamp',
text: 'Timestamp',
flex: 1
}]
}, {
region: 'center',
xtype: 'panel',
layout: {
type: 'vbox'
},
bodyPadding: 8,
items: [{
xtype: 'container',
layout: 'hbox',
margin: '8 0 0 0',
items: [{
xtype: 'textfield',
reference: 'txtTimestampIn',
fieldLabel: 'Timestamp In'
}, {
xtype: 'button',
itemId: 'btnSetTime',
text: 'Set Time',
margin: '0 0 0 12'
}]
}, {
xtype: 'container',
layout: 'hbox',
margin: '8 0 0 0',
items: [{
xtype: 'datetimefield',
name: 'startDate',
itemId: 'startDate',
reference: 'startDate',
dateConfig: {
fieldLabel: 'Start'
},
listeners: {
afterrender: {
fn: me.dateTimeField_onComplete,
scope: me
}
}
}, {
xtype: 'button',
itemId: 'btnExportTime',
text: 'Get Time',
margin: '0 0 0 12'
}]
}, {
xtype: 'textfield',
reference: 'txtTimestampOut',
fieldLabel: 'Timestamp Out',
margin: '8 0 0 0'
}]
}],
me.callParent();
},
dateTimeField_onComplete: function (field, eOpts) {
var me = this,
timestamp = timestampData[0][0];
field.setValue(timestamp);
}
});
////////////////////////////////////////////////////////////
// Controllers
////////////////////////////////////////////////////////////
Ext.define('DateTime.controller.MainController', {
extend: 'Ext.app.Controller',
views: ['DateTime.view.MainView'],
mixins: {
utils: 'DateTime.mixin.CommonUtils'
},
refs: [{
ref: 'mainView',
selector: 'mainView'
}],
init: function () {
var me = this;
me.control({
'#startDate': {
dateFieldChange: me.handleDateChange
},
'#btnSetTime': {
click: me.handleSetTime
},
'#btnExportTime': {
click: me.handleExportTime
},
'#timestampList' : {
selectionchange: me.handleChangeTimestamp
}
});
},
handleDateChange: function (field, newValue, oldValue) {
// Do nothing...
},
handleSetTime: function (button, e, eOpts) {
var me = this,
view = me.getMainView(),
timestampIn = view.lookupReference('txtTimestampIn');
view.lookupReference('startDate').setValue(timestampIn.getValue());
me.handleExportTime();
},
handleExportTime: function (button, e, eOpts) {
var me = this,
toISOStr = me.mixins.utils.dateToISOString,
view = me.getMainView(),
timestampIn = view.lookupReference('txtTimestampOut');
timestampIn.setValue(toISOStr(view.lookupReference('startDate').getValue()));
},
handleChangeTimestamp: function(grid, selected, eOpts) {
var me = this,
view = me.getMainView(),
timestamp = selected[0].data.timestamp;
view.lookupReference('txtTimestampIn').setValue(timestamp);
me.handleSetTime();
}
});
//////////////////////////////////////////////////////////
// Applications
//////////////////////////////////////////////////////////
Ext.define('DateTime.app.DateTimeApp', {
extend: 'Ext.app.Application',
name: 'DateTimeApp',
controllers: ['DateTime.controller.MainController'],
launch: function () {
Ext.create('Ext.Viewport', {
layout: 'fit',
flex: 1,
items: [{
xtype: 'mainview'
}]
});
}
});
//////////////////////////////////////////////////////////
// Startup
//////////////////////////////////////////////////////////
Ext.onReady(function () {
Ext.application('DateTime.app.DateTimeApp');
});
Looks like I figured it out, although there is still an issue. The selected time does not appear in the dropdown... It just does not appear which is very strange. If anyone has a suggestion, comment below, or add your own answer.
Anyways, If anyone needs a UTC date-time field, here it is. I cleaned it up a bit. I completely refactored the code from my question so that timezone information is irrelevant. Date are explicitly converted from UTC to local and vice versa. This way, there is no need to calculate anything.
Ext.ux.form.field.DateTimeField
Ext.define('DateTime.components.DateTimeField', {
extend: 'Ext.container.Container',
mixins: ['Ext.form.field.Field'],
alias: 'widget.datetimefield',
config: {
dateConfig: {},
timeConfig: {},
utcValue: true,
hideDate: false
},
referenceHolder: true,
layout: {
type: 'hbox'
},
initComponent: function () {
var me = this,
today = new Date(),
dateConfig = me.dateConfig,
timeConfig = me.timeConfig;
me.items = [Ext.apply({
xtype: 'datefield',
reference: 'dateField',
fieldLabel: 'Date',
value: today,
listeners: {
change: function (field, newValue, oldValue) {
me.fireEvent('dateFieldChange', field, newValue, oldValue);
}
}
}, dateConfig),
Ext.apply({
xtype: 'timefield',
reference: 'timeField',
format: 'H:i',
value: '00:00',
maxValue: '24:00',
increment: 15,
padding: '0 0 0 10',
width: 80
}, timeConfig)];
me.callParent();
},
afterRender: function () {
var me = this;
if (me.hideDate) {
me.getDateField().hide();
}
me.callParent();
},
getValue: function () {
var me = this;
var dateTime = me.combineDateTime(me.getDate(), me.getTime());
if (me.utcValue) {
return me.localToUtc(dateTime);
}
return dateTime;
},
setValue: function(value) {
var me = this;
if (value == null) {
return;
}
if (Ext.isString(value)) {
value = Ext.Date.parse(value, 'c');
}
if (value != null && Ext.isDate(value)) {
var timeDate = Ext.clone(value);
if (me.utcValue) {
timeDate = this.utcToLocal(timeDate);
}
me.setDate(timeDate);
me.setTime(timeDate);
}
},
getTimeField : function() {
return this.lookupReference('timeField');
},
getDateField : function() {
return this.lookupReference('dateField');
},
getTime: function() {
return this.getTimeField().getValue();
},
setTime: function(value) {
this.getTimeField().setValue(value);
},
getDate: function() {
return this.getDateField().getValue();
},
setDate: function(value) {
this.getDateField().setValue(value);
},
combineDateTime : function(date, time) {
var year = date.getFullYear();
var month = date.getMonth();
var day = date.getDate();
var hour = time.getHours();
var minute = time.getMinutes();
var second = time.getSeconds();
return new Date(year, month, day, hour, minute, second, 0);
},
utcToLocal : function(utcDate) {
var year = utcDate.getUTCFullYear();
var month = utcDate.getUTCMonth();
var day = utcDate.getUTCDate();
var hour = utcDate.getUTCHours();
var minute = utcDate.getUTCMinutes();
var second = utcDate.getUTCSeconds();
return new Date(year, month, day, hour, minute, second, 0);
},
localToUtc : function(localDate) {
var year = localDate.getFullYear();
var month = localDate.getMonth();
var day = localDate.getDate();
var hour = localDate.getHours();
var minute = localDate.getMinutes();
var second = localDate.getSeconds();
return new Date(Date.UTC(year, month, day, hour, minute, second, 0));
}
});
Demos
JSFiddle
SenchaFiddle
Related
extjs combo box getCount() on store returns 0
I am trying to get the number of items in the combo box so that I can make the first value by default visible in the combo box using the getCount() method but I see it always return 0 so cannot get the first item to be displayed in the combo box. Code for my combo box is as shown below: Ext.define('something....', { controller: 'some Controller', initComponent: function() { var me, me = this; me.items = [{ xtype: 'form', items: [{ xtype: 'combo', itemId: 'nameId', name:'nameId', labelAlign: 'top', fieldLabel: 'Name', store: me._getNames(), //disabled:some condition?true:false,//doesn't gray out combo valueField:'dataId', displayField: 'firstName', editable: false, listeners:{ afterrender: function(combo,component) { var combo = me.down('#nameId'); var nameStore = combo.getStore(); var setFirstRecord = function(combo){ var nameStore = combo.getStore(); if(nameStore.getCount() === 1){ combo.setValue(nameStore.getAt(0)); } } if(nameStore.isLoaded() === false){ nameStore.on('load', function(nameStore){ setFirstRecord(combo); },this,{ single:true }); }else{ setFirstRecord(nameStore); } }, } }] }]; } Code for the store is as below: _getNames: function (){ var nameStore = Ext.create('Ext.data.Store', { autoLoad: true, proxy: { type: 'ajax', url: 'name.json', reader: { type: 'json', rootProperty:'items', transform: function (data) { var data = { items: [{ dataId: data[0].dataId, firstName: data[0].name.firstName, nameDetails: data[0].nameDetails }] } return data; } }, }, fields: ['dataId', 'firstName','nameDetails'] }); return namesStore; } }) The result returned from the api to populate the store is as follows: [ { "dataId":1, "name":{ "dataId":1, "firstName":"Julie", "code":"10", "connectionList":[ "EMAIL" ] }, "nameDetails":{ "EMAIL":{ "dataId":1, "detail":"EMAIL" } } } ] Any suggestions on what's missing would be great!
I am written that example for you in Sencha Fiddle: https://fiddle.sencha.com/#view/editor&fiddle/3cdl That solve your problem: combo.getStore().on("load", function (store, records, successful, operation, eOpts) { if (store.getData().length > 0) combo.setValue(store.getData().get(0).getData().id) }, this )
You must check if store is loaded or not and write appropriate code: ... ... xtype: 'combo', itemId: 'nameId', name: 'nameId', labelAlign: 'top', fieldLabel: 'Name', store: this._getNames(), valueField: 'dataId', displayField: 'firstName', editable: false, listeners: { afterrender: function (combo) { var store = combo.getStore(); var setFirstRecord = function (combo) { var store = combo.getStore(); if (store.getCount() === 1) { combo.setValue(store.getAt(0)); } } if (store.isLoaded() === false) { store.on('load', function (store) { setFirstRecord(combo); }, this, { single: true }); } else { setFirstRecord(combo); } } } ... ...
Datatables date sort vs date display
I am using Datatables to display a table and I am pulling a list of datestimes from a MySQL database. These date times are not standard dates and look like this: 12/30/19 # 04:17 pm How can I sort these accurately with Datatables? Here is my code: getRes(function (result) { // APPLIED CALLBACK $('#resdatatable').DataTable({ data: result, // YOUR RESULT order: [[ 0, "desc" ]], autoWidth: false, responsive: true, columns: [ { data: 'id', title: 'ID' }, { data: 'bookingdatetime', title: 'Booking Date' }, { data: 'name', title: 'Name' }, { data: 'class', title: 'Class' }, { data: 'pickupdatetime', title: 'Pick up' }, { data: 'duration', title: 'Duration' }, { data: 'dropdatetime', title: 'Drop off' }, { data: 'age', title: 'Age' }, { data: 'coverage', title: 'Coverage' }, { data: 'quote', title: 'Quote' }, { data: 'status', title: 'Status', render: function(data, type, row) { let isKnown = statusList.filter(function(k) { return k.id === data; }).length > 0; if (isKnown) { return $('<select id="resstatus'+row.id+'" onchange="changeResStatus('+row.id+')" data-previousvalue="'+row.status+'">', { id: 'resstatus-' + row.id, // custom id value: data }).append(statusList.map(function(knownStatus) { let $option = $('<option>', { text: knownStatus.text, value: knownStatus.id }); if (row.status === knownStatus.id) { $option.attr('selected', 'selected'); } return $option; })).on('change', function() { changeresstatus(row.id); // Call change with row ID }).prop('outerHTML'); } else { return data; } } } ] }); }); /** * jQuery plugin to convert text in a cell to a dropdown */ (function($) { $.fn.createDropDown = function(items) { let oldTxt = this.text(); let isKnown = items.filter(function(k) { return k.id === oldTxt; }).length > 0; if (isKnown) { this.empty().append($('<select>').append(items.map(function(item) { let $option = $('<option>', { text: item.text, value: item.id }); if (item.id === oldTxt) { $option.attr('selected', 'selected'); } return $option; }))); } return this; }; })(jQuery); // If you remove the renderer above and change this to true, // you can call this, but it will run once... if (false) { $('#resdatatable > tbody tr').each(function(i, tr) { $(tr).find('td').last().createDropDown(statusList); }); } function getStatusList() { return [{ id: 'Confirmed', text: 'Confirmed' }, { id: 'Unconfirmed', text: 'Unconfirmed' }, { id: 'Communicating', text: 'Communicating' }, { id: 'Open', text: 'Open' }, { id: 'Closed', text: 'Closed' }, { id: 'Canceled', text: 'Canceled' }, { id: 'Reallocated', text: 'Reallocated' }, { id: 'No Show', text: 'No Show' }]; } I need to sort bookingdatetime, pickupdatetime, dropdatetime accurately (they are currently being converted into MM/DD/YY in the PHP script)
Maybe you can prepend hidden <span> elements containing the respective unix timestamps in the cells that have dates (by manually parsing the dates). Then using such columns to sort alphabetically would practically sort time-wise.
EXTJS Window/Panel close error
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
sencha navigation view overlapping on home listview
I am using sencha navigation view in my sencha application . my bug scenario I have list view with images on home screen first time it's load 20 record then scroll to down record will be increase by 20 on every scroll when i click on any image and redirect to another view like image detail view or profile view and come back to home on pressing back button all the images overlapped. please help i am trying to solve this bug before 10 day's but not get success :- before overlapping 1) I am using navigation view it's extend with "Ext.dataview.DataView" and there is using useComponents: true, defaultType: 'productlistitem' 2) In 'productlistitem' extend with 'Ext.dataview.component.DataItem' In this view I am using update method witch set the image and other component data and also using dynamically method for image width , height . below you can check my all views code A) Home.js Ext.define('demo.view.home.Home', { extend: 'Ext.dataview.DataView', requires: [ 'demo.view.product.ListItem', 'demo.view.layout.ColumnLayout' ], xtype: 'home', config: { scrollable: true, plugins: { xclass: 'demo.plugin.DataViewPaging', // Reference plugin by class autoPaging: true }, autoDestroy: true, store: 'LookStore', margin:'2 0', useComponents: true, defaultType: 'productlistitem', cls: 'wow-home', layout: { type: 'column', columnCount: 2, columnWidth: 160 } } }); B) ListItem.js var listItemData=[]; Ext.define('demo.view.product.ListItem', { extend: 'Ext.dataview.component.DataItem', requires: ['demo.view.product.Item'], xtype: 'productlistitem', config: { padding: 2, zIndex:999, items: [{ xtype: 'item' }] }, initialize: function() { console.log('initing the list item '); var me = this; me.callParent(arguments); this.on('heightchange', 'recalculateHeight', me, { delegate: '> item' }); }, recalculateHeight: function() { var me = this; me.setHeight(me.innerElement.getHeight()); }, updateRecord: function(record) { if (!record) { return; } var me = this, item = me.down('item'); me.callParent(arguments); if (item) { item.updateRecord(record, me.getDataview()); } listItemData.push(item.id); } }); c) Item.js Ext.define('demo.view.product.Item', { extend: 'Ext.Container', xtype: 'item', requires: [ 'Ext.Carousel', 'demo.view.product.ItemImage', 'demo.view.product.UserInfo', 'demo.view.product.InfoLabel' ], config: { record: null, baseCls: 'wow-item', showDescription: false, items: [{ xtype: 'itemimage', width: '100%' }, { xtype: 'userinfo', height: 40, listeners: { painted: function() { if (!this.element.hasListener('tap')) { this.element.on('tap', function(e) { e.stopPropagation(); var record = this.scope.up('item').getRecord(); if (!this.scope.getHandleListeners()) { if(Ext.ComponentQuery.query('main')[0].getActiveItem().xtype === "wardrobedrawer") demo.app.getController('ProductController').openProductDetail('', '', '', record); return; } if (record && !Ext.isEmpty(record.raw.product_id) && !Ext.isEmpty(record.raw.importer)) { var brandMerchantProducts = this.scope.up('brandmerchantproducts'); if (brandMerchantProducts) { var currentTitle = demo.app.getController('HomeController').getMain().getActiveItem().config.title; var currentItem = this.scope.element.dom.textContent; if (currentTitle.toUpperCase() !== currentItem.toUpperCase()) { demo.app.getController('ProductController').showMerchantProducts(record); } return; } demo.app.getController('ProductController').showMerchantProducts(record); } else { var list = this.scope.up('list'); demo.app.getController('ProfileController').goToOtherUserProfile(list, null, null, record.get('merchantId'), e); } }, { scope: this }); } } } }, { xtype: 'container', height: 40, margin:'1 0 0 0', name: 'infoContainer', layout:'hbox', defaults: { xtype: 'infolabel', flex: 1 }, items: [{ iconCls: 'icon-diamond', text: '09', itemId: 'wows', listeners: { painted: function() { if (!this.element.hasListener('tap')) { this.element.on('tap', function(e) { e.stopPropagation(); var record = this.scope.up('item').getRecord(); if (record.get('type') == 'product') { demo.app.getController('ProductController').wowOrUnwowHomeProduct(record, this.scope.up('item')); } if (record.get('type') === 'look') { demo.app.getController('ProductController').wowOrUnwowHomeLook(record, this.scope.up('item')); } }, { scope: this }); } } } }, { iconCls: 'icon-drawer', text: '11', itemId: 'lookOrAdd', listeners: { painted: function() { if (!this.element.hasListener('tap')) { this.element.on('tap', function(e) { e.stopPropagation(); var record = this.scope.up('item').getRecord(); if (record.get('type') == 'product') { demo.addedProductItem = this.scope.up('item'); demo.app.getController('ProductController').addProduct(record); } if (record.get('type') === 'look') { demo.app.getController('ProductController').addHomeLook(record, this.scope.up('item')); } }, { scope: this }); } } } }] } ] }, initialize: function() { var me = this; me.callParent(arguments); me.on('load', 'imageLoaded', me, { delegate: 'itemimage' }); }, imageLoaded: function() { var me = this; me.setHeight(me.element.getHeight()); }, updateRecord: function(item, dataview) { if (!item) { return; } if (dataview && dataview.config.showDescription) { this.setShowDescription(true); } var me = this; me.setRecord(item); if (item) { var itemImage = this.down('itemimage'), images = item.get('images'), wows = item.get('wows') + '', adds = item.get('adds') + '', userInfo = this.down('userinfo'); if (images && images.length) { itemImage.setSrc(images[0].original); } var type = item.get('type'); var lookOrProduct = me.down('#lookOrAdd'); var added = item.get('added'); var icon; if (type === 'product') { icon = 'icon-add-drawer'; lookOrProduct.setIconCls(icon); } else { icon = added ? 'icon-counterlook' : 'icon-addlookbook'; lookOrProduct.setIconCls(icon); } if (!Ext.isEmpty(item.raw.product_id)) { userInfo.setAvatar(''); } else { // USER var importer = item.get('importer'); if (importer) { var avatar = importer.avatar; if (avatar) { userInfo.setAvatar(avatar); } else { userInfo.setAvatar('resources/images/default/default_avatar.jpg'); } } } me.down('#wows').setText(wows); if (!item.get('wowed')) { me.down('#wows').addCls('grayedout-cls'); } else { me.down('#wows').removeCls('grayedout-cls'); } lookOrProduct.setText(adds); if (!item.get('added')) { lookOrProduct.addCls('grayedout-cls'); } else { lookOrProduct.removeCls('grayedout-cls'); } var infoContainer = this.down('container[name=infoContainer]'); if (infoContainer && infoContainer.isHidden()) { infoContainer.show(); } var title = Ext.ComponentQuery.query('main')[0].getActiveItem().title; var storeId = this._record.stores[0].getStoreId(); if (type === 'product' && !Ext.isDefined(title) && storeId !== 'WowedStore' && storeId !== 'SearchStore' && storeId !== 'BrandMerchatProducts') { var homeUrl = this._record.stores[0].getProxy().getUrl(); if ((homeUrl === demo.model.Config.apiServerPath('home')) || (homeUrl === demo.model.Config.apiServerPath('home'))) { var noOfProducts = Ext.ComponentQuery.query('#productsInTheListId').length; if (noOfProducts === 1) { userInfo.setUsername(item); if (me.getShowDescription()) { infoContainer.hide(); userInfo.setAvatar(''); userInfo.setUsername(item); userInfo.setHandleListeners(false); } } else { userInfo.setUsername(item.get('author')); if (me.getShowDescription()) { infoContainer.hide(); userInfo.setAvatar(''); userInfo.setUsername(item.get('description')); userInfo.setHandleListeners(false); } } } else { userInfo.setUsername(item); if (me.getShowDescription()) { infoContainer.hide(); userInfo.setAvatar(''); userInfo.setUsername(item); userInfo.setHandleListeners(false); } } } else { userInfo.setUsername(item.get('author')); if (me.getShowDescription()) { infoContainer.hide(); userInfo.setAvatar(''); userInfo.setUsername(item.get('description')); userInfo.setHandleListeners(false); } } } }, updateColorOfItem: function(item) { var me = this, lookOrProduct = me.down('#lookOrAdd'); if (!item.get('wowed')) { me.down('#wows').addCls('grayedout-cls'); } else { me.down('#wows').removeCls('grayedout-cls'); } if (!item.get('added')) { lookOrProduct.addCls('grayedout-cls'); } else { lookOrProduct.removeCls('grayedout-cls'); } } }); D) ItemImage.js Ext.define('demo.view.product.ItemImage', { extend: 'Ext.Img', xtype: 'itemimage', config: { }, onLoad: function(event) { var me = this, width = me.getParent().element.getWidth(), // me.element.getWidth() should work but I have found that sometimes it gives a width of 0. Now I go with a width of the parent. imageObject = me.imageObject, naturalWidth = imageObject.width, naturalHeight = imageObject.height, naturalRatio = naturalHeight / naturalWidth, newHeight = naturalRatio * width; me.setHeight(newHeight); //Ext.ComponentQuery.query('productlistitem')[0].setHeight(newHeight+84); me.callParent(event); } }); E) UserInfo.js Ext.define('demo.view.product.UserInfo', { extend: 'Ext.Container', requires: ['Ext.Img'], xtype: 'userinfo', config: { avatar: null, username: null, baseCls: 'wow-user-info', handleListeners: true }, applyAvatar: function(avatar) { if (Ext.isEmpty(avatar)) { return null; } return Ext.factory({ src: avatar, cls: 'wow-avatar', docked: 'left' }, 'Ext.Img'); }, updateAvatar: function(newAvatar, oldAvatar) { if (newAvatar) { this.add(newAvatar); } if (oldAvatar) { oldAvatar.destroy(); } }, applyUsername: function(item) { if (Ext.isObject(item)) { var price_value = "", price_currency = "", itemName = ""; if (Ext.isDefined(item.raw.price)) { if (Ext.isDefined(item.raw.price.value)) { price_value = item.raw.price.value.toString(); } } if (Ext.isDefined(item.raw.price)) { if (Ext.isDefined(item.raw.price.currency)) { price_currency = item.raw.price.symbol; } } if (item.raw.description === null) { var item = item.data.author; } else { var item = item.raw.description; } item = item.toLowerCase(); itemName = item.charAt(0).toUpperCase() + item.slice(1); if (Ext.isDefined(price_currency) && Ext.isDefined(price_value) && (price_currency !== "") && (price_value !== "")) { itemName = '<div class="itemNames"><span style="font-size:0.9em" >' + price_currency.bold() + ' ' + price_value.bold() + '</span>' + " " + '<span style=" font-size:0.8em" class="itemName">' + itemName + '</span>' + '</div>'; } else { itemName = '<div class="itemNames"><span style=" font-size:0.8em" class="itemName">' + itemName + '</span></div>'; } return Ext.factory({ html: itemName, xtype: 'component', cls: 'wow-username-product' }); } else { return Ext.factory({ html: item, xtype: 'component', cls: 'wow-username' }); } }, updateUsername: function(newUsername, oldUsername) { if (newUsername) { this.add(newUsername); } if (oldUsername) { oldUsername.destroy(); } } }); F) InfoLabel.js Ext.define('demo.view.product.InfoLabel', { extend: 'Ext.Button', xtype: 'infolabel', config: { iconAlign: 'left', cls: 'wow-info-label' }, initialize: function() { // Do nothing stopping unnecessary event listeners being added. } });
commit changes on existing records in extjs store
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.