Using Ext 4.1 I'd like to create a form with select combo, and depending on the currently selected option different subfields would be shown/hidden. Example below :
Right now I have a combo and a set of two date fields that are hidden on render. When a combo value is changed I have an event listener that will display those fields. But I'm not sure if it's the best method to tackle this. Would a fieldset work better in this case ?
Ext.define('TooltipForm', {
extend: 'Ext.form.Panel',
layout: {
type: 'vbox',
align: 'stretch'
},
border: false,
bodyPadding: 10,
initComponent: function(){
this.on('afterrender', this.onAfterRender, this);
this.callParent(arguments);
},
onAfterRender: function(){
this.items.each(function(item){
item.on('change', this.onChange, this);
}, this);
},
onChange: function(field, newValue){
if (field.name === 'range'){
switch(newValue){
case 'fit':
console.log('fit view');
break;
case 'complete':
console.log('complete view');
break;
case 'date range':
console.log('date range view');
break;
}
}
},
fieldDefaults: {
labelAlign: 'top',
labelWidth: 100,
labelStyle: 'font-weight:bold'
},
items: [
{
width: 50,
xtype: 'combo',
mode: 'local',
value: 'fit',
triggerAction: 'all',
forceSelection: true,
editable: false,
fieldLabel: me.rangeFieldLabel,
name: 'range',
queryMode: 'local',
store: ['fit', 'complete', 'date range']
},
{
width:50,
xtype: 'datefield',
fieldLabel: 'date from',
name: 'datefrom',
hidden: true
},
{
width:50,
xtype: 'datefield',
fieldLabel: 'date to',
name: 'dateto',
hidden:true,
}
]
});
Something along these lines:
Ext.define('TooltipForm', {
extend: 'Ext.form.Panel',
layout: {
type: 'vbox',
align: 'stretch'
},
border: false,
bodyPadding: 10,
rangeFieldLabel: 'Foo',
initComponent: function() {
Ext.apply(this, {
fieldDefaults: {
labelAlign: 'top',
labelWidth: 100,
labelStyle: 'font-weight:bold'
},
items: [{
itemId: 'range',
width: 50,
xtype: 'combo',
value: 'fit',
triggerAction: 'all',
forceSelection: true,
editable: false,
fieldLabel: this.rangeFieldLabel,
name: 'range',
queryMode: 'local',
store: ['fit', 'complete', 'date range']
}, {
itemId: 'dateFrom',
width: 50,
xtype: 'datefield',
fieldLabel: 'date from',
name: 'datefrom',
hidden: true
}, {
itemId: 'dateTo',
width: 50,
xtype: 'datefield',
fieldLabel: 'date to',
name: 'dateto',
hidden: true,
}]
});
this.callParent(arguments);
this.child('#range').on('change', this.onChange, this);
},
onChange: function(field, newValue) {
switch(newValue) {
case 'fit':
console.log('fit view');
// do something else
break;
case 'complete':
this.child('#dateFrom').hide();
this.child('#dateTo').hide();
break;
case 'date range':
this.child('#dateFrom').show();
this.child('#dateTo').show();
break;
}
},
});
Ext.onReady(function(){
new TooltipForm({
renderTo: document.body
});
});
Related
I have 2 grids on a window which support drag and drop each by himself and also between each other.
I can't get the vertical scroll to work when dragging above the first row in the grid or below the last row in the grid.
currently, i must first scroll all the way down if i want to drag the record to the bottom of the grid.
using containerScroll didn't solve the problem.
Ext.define('MyApp.view.DDFieldsGrid', {
extend: 'Ext.grid.Panel',
xtype: 'ddfieldsgrid',
hideHeaders: true,
multiSelect: true,
autoScroll: true,
markDirty: false,
columns: [
{ dataIndex: 'item', flex: 1 }
],
viewConfig: {
plugins: {
containerScroll: true,
ptype: 'gridviewdragdrop',
ddGroup: 'firstGridDDGroup'
}
}
});
this.mainWin = Ext.create('Ext.window.Window', {
layout: 'centered',
title: 'Blotter Fields',
resizable: false,
closeAction: 'hide',
hidden: true,
shadow: true,
tbar: [{
xtype: 'combo',
fieldLabel: 'Fields Type',
id: 'comboCategories',
editable: false,
queryMode: 'local',
selectOnFocus: true,
forceSelection: true,
iconCls: 'no-icon',
triggerAction: 'all',
store: categoreyItems,
listeners: {
select: function (ele, newValue, oldValue) {
var category = this.valueModels[0].index;
var store = Ext.getStore('availableFields');
store.filterBy(function (record) {
return category == 0 /*All*/ || record.get('category') === category;
}, this);
}
}
}, ' ', {
xtype: 'checkbox',
fieldLabel: 'Show Details field',
margin: '0 10 0 20',
//hidden: this.customizationModel._customizationView.detailsCustomOptions.showDetailsFieldsOption == false,
checked: this.customizationModel._customizationView.detailsCustomOptions.showDetailsFieldsOption,
listeners: {
click: {
fn: this.onShowDetailsField,
scope: this
}
}
}, ' ', {
xtype: 'checkbox',
fieldLabel: 'Show custom fields',
margin: '0 10 0 20',
//hidden: this.customizationModel._customizationView.detailsCustomOptions.showUserCustomFieldsOptions == false,
checked: this.customizationModel._customizationView.detailsCustomOptions.showUserCustomFieldsOptions,
listeners: {
click: {
fn: this.onShowCustomFields,
scope: this
}
}
}],
dockedItems: [
{
xtype: 'toolbar',
flex: 1,
dock: 'bottom',
layout: {
pack: 'end',
type: 'hbox'
},
items: [
{
xtype: 'button',
text: 'Cancel',
listeners: {
click: {
fn: this.onCancelSettings,
scope: this
}
}
},
{
xtype: 'button',
text: 'OK',
listeners: {
click: {
fn: this.onAcceptSettings,
scope: this
}
}
}
]
}
],
items: [{
store: availableFieldsStore,
title: 'Available Fields'
}, {
store: selectedFieldsStore,
title: 'Selected Fields'
}],
layout: {
type: 'hbox',
align: 'stretch'
},
defaults: {
xtype: 'ddfieldsgrid',
height: 200,
margin: 8,
width: 300
}
});
Hello I've problem to selected by value. And the data is from viewmodel. I also search the answer on google but I not found. I am very confusing about it. Please help me.
This is my form:
Ext.define('Sipen.view.items.ItemsForm', {
extend: 'Ext.window.Window',
xtype: 'items-form',
height: 250,
width: 500,
layout: { type: 'fit' },
bind: {title: '{title}'},
modal: true,
items: [
{
xtype: 'form',
reference: 'form',
bodyPadding: 20,
flex: 1,
modelValidation: true,
layout: {
type: 'hbox',
align: 'stretch'
},
items: [
{
xtype: 'fieldcontainer',
flex: 1,
title: 'Item Information',
layout: 'anchor',
defaults: {
anchor: '100%',
xtype: 'textfield',
msgTarget: 'under',
labelWidht: 100,
allowBlank: false
},
items: [
{
xtype: 'hiddenfield',
name: '_id',
bind: '{currentTipe._id}'
},
{
fieldLabel: 'Code',
name: 'item_code',
bind: '{currentItem.item_code}'
},
{
fieldLabel: 'Name',
name: 'item_name',
bind: '{currentItem.item_name}'
},
{
xtype: 'numberfield',
minValue: 1,
fieldLabel: 'Price',
name: 'item_price',
bind: '{currentItem.item_price}'
},
{
xtype: 'combo',
name: 'type',
fieldLabel: 'Type',
valueField: 'type_name',
displayField: 'type_name',
queryMode: 'local',
forceSelection: true,
submitValue: true,
bind: {
value: '{typeItems.type_name}',
store: '{typeItems}',
selection: '{currentItem.type_name}'
}
}
]
}
],
dockedItems: [
{
xtype: 'toolbar',
dock: 'bottom',
ui: 'footer',
layout: {
pack: 'end',
type: 'hbox'
},
items: [
{
xtype: 'button',
text: 'Save',
formBind: true,
listeners: {
click: 'onSave'
}
},
{
xtype: 'button',
text: 'Cancel',
listeners: {
click: 'onCancel'
}
}
]
}
]
}
]
});
Look at xtype 'combo' and I selection data by {currentItem.type_name} and the data is right, but I get error
this Uncaught TypeError: item.getId is not a function.
And this is my view model:
Ext.define('Sipen.view.items.ItemsModel', {
extend: 'Ext.app.ViewModel',
alias: 'viewmodel.items-items',
requires: [ 'Sipen.model.Items' ],
stores: {
items: {
model: 'Items',
autoLoad: true
},
typeItems: {
model: 'TypeItems',
autoLoad: true
}
}
});
Sorry for my bad english, but please help me...
============[Fixed]======================
I've found the result in here https://www.sencha.com/forum/showthread.php?302067
So the script should be like this:
{
xtype: 'combo',
name: 'type',
fieldLabel: 'Type',
valueField: 'type_name',
displayField: 'type_name',
queryMode: 'local',
forceSelection: true,
submitValue: true,
bind: {
value: '{typeItems.type_name}',
store: '{typeItems}',
selection: '{currentItem.type_name}'
}
}
I have a form that has comboboxes, tagfields, date pickers, etc., and a grid. Each of these elements has a different store. The user is going to make selections from the comboboxes, etc,. and enter values into the grid. Then the values from the grid and other form elements are all sent on a POST to the server. I know how to POST the data from the comboboxes, tagfields, and date pickers. However, I don't know how to send the data in the grid with the form. Here is the form view:
Ext.define('ExtTestApp.view.main.List', {
extend: 'Ext.form.Panel',
xtype: 'cell-editing',
frame: true,
autoScroll: true,
title: 'Record Event',
bodyPadding: 5,
requires: [
'Ext.selection.CellModel',
'ExtTestApp.store.Personnel'
],
layout: 'column',
initComponent: function(){
this.cellEditing = new Ext.grid.plugin.CellEditing({
clicksToEdit: 1
});
Ext.apply(this, {
//width: 550,
fieldDefaults: {
labelAlign: 'left',
labelWidth: 90,
anchor: '100%',
msgTarget: 'side'
},
items: [{
xtype: 'fieldset',
//width: 400,
title: 'Event Information',
//height: 460,
//defaultType: 'textfield',
layout: 'anchor',
defaults: {
anchor: '100%'
},
items: [{
xtype: 'fieldcontainer',
fieldLabel: 'Event',
layout: 'hbox',
defaults: {
hideLabel: 'true'
},
items: [{
xtype: 'combobox',
name: 'eventTypeId',
width: 300,
//flex: 1,
store: {
type: 'events'
},
valueField: 'eventTypeId',
// Template for the dropdown menu.
// Note the use of the "x-list-plain" and "x-boundlist-item" class,
// this is required to make the items selectable.
allowBlank: false
}
]
},
{
xtype: 'container',
layout: 'hbox',
margin: '0 0 5 0',
items: [
{
xtype: 'datefield',
fieldLabel: 'Date',
format: 'Y-m-d',
name: 'startDate',
//msgTarget: 'under', //location of error message, default is tooltip
invalidText: '"{0}" is not a valid date. "{1}" would be a valid date.',
//flex: 1,
emptyText: 'Start',
allowBlank: false
},
{
xtype: 'datefield',
format: 'Y-m-d',
name: 'endDate',
//msgTarget: 'under', //location of error message
invalidText: '"{0}" is not a valid date. "{1}" would be a valid date.',
//flex: 1,
margin: '0 0 0 6',
emptyText: 'End',
allowBlank: false
}
]
}]
},
{
xtype: 'fieldset',
//height: 460,
title: 'Platform Information',
//defaultType: 'textfield',
layout: 'anchor',
defaults: {
anchor: '100%'
},
items: [
{
xtype: 'fieldcontainer',
layout: 'hbox',
fieldLabel: 'Platform',
//combineErrors: true,
defaults: {
hideLabel: 'true'
},
items: [
{
xtype: 'combobox',
name: 'platformId',
store: {
type: 'platforms'
},
valueField: 'platformId',
allowBlank: false
}
]
}
]
},
{
xtype: 'fieldcontainer',
layout: 'hbox',
fieldLabel: 'Software Type(s)',
//combineErrors: true,
defaults: {
hideLabel: 'true'
},
items: [
{
xtype: 'tagfield',
width: 400,
//height: 50,
fieldLabel: 'Software Type(s)',
name: 'softwareTypeIds',
store: {
type: 'softwareTypes'
},
labelTpl: '{softwareName} - {manufacturer}',
valueField: 'softwareTypeId',
allowBlank: false
}
]
},
{
xtype: 'gridpanel',
layout: 'anchor',
defaults: {
anchor: '100%'
},
width: 1300,
//columnWidth: 0.78,
//title: 'Metrics',
plugins: [this.cellEditing],
title: 'Personnel',
store: {
type: 'personnel'
},
columns: [
{ text: 'Name', dataIndex: 'name', editor: 'textfield' },
{ text: 'Email', dataIndex: 'email', flex: 1 },
{ text: 'Phone', dataIndex: 'phone', flex: 1 }
]
}
],
buttons: [
{
text: 'Save Event',
handler: function() {
var form = this.up('form'); // get the form panel
// if (form.isValid()) { // make sure the form contains valid data before submitting
Ext.Ajax.request({
url: 'api/events/create',
method:'POST',
headers: { 'Content-Type': 'application/json' },
params : Ext.JSON.encode(form.getValues()),
success: function(form, action) {
Ext.Msg.alert('Success', action.result);
},
failure: function(form, action) {
//console.log(form.getForm().getValues());
Ext.Msg.alert('Submission failed', 'Please make sure you selected an item for each required field.', action.result);
}
});
// } else { // display error alert if the data is invalid
// Ext.Msg.alert('Submit Failed', 'Please make sure you have made selections for each required field.')
// }
}
}
]
});
this.callParent();
}
});
var grid = Ext.ComponentQuery.query('grid')[0];
Here is the store for the grid:
Ext.define('ExtTestApp.store.Personnel', {
extend: 'Ext.data.Store',
alias: 'store.personnel',
fields: [
'name', 'email', 'phone'
],
data: { items: [
{ name: 'Jean Luc', email: "jeanluc.picard#enterprise.com", phone: "555-111-1111" },
{ name: 'Worf', email: "worf.moghsson#enterprise.com", phone: "555-222-2222" },
{ name: 'Deanna', email: "deanna.troi#enterprise.com", phone: "555-333-3333" },
{ name: 'Data', email: "mr.data#enterprise.com", phone: "555-444-4444" }
]},
autoLoad: true,
proxy: {
type: 'memory',
api: {
update: 'api/update'
},
reader: {
type: 'json',
rootProperty: 'items'
},
writer: {
type: 'json',
writeAllFields: true,
rootProperty: 'items'
}
}
});
Ideally, you would need to create a custom "grid field" so that the grid data is picked up on form submit like any other field.
You can also use this workaround: in the "Save Event" button handler, dig out the grid store and fish data out of it:
var gridData = [];
form.down('gridpanel').store.each(function(r) {
gridData.push(r.getData());
});
Then get the rest of the form data and put the grid data into it:
var formData = form.getValues();
formData.gridData = gridData;
Finally, include it all in your AJAX call:
params: Ext.JSON.encode(formData)
1) Create a grid and add a coulmn of type 'timefield' in grid with renderer of format ('h:i A').
2) Add a row and mke a selection in 'timefield' column, say 4:00 AM.
3) Add another adjecent row and select the same data i.e. 4:00 AM in the dropdown. You will not be able to do this action, and you need to select another time and then come back to the initial selection. It looks to be an ExtJS bug. how to solve this issue.
I have code the following in grid
this.mcmGridPanel = new Ext.grid.GridPanel({ height: 360, width: 680, title: 'Shifts', store: App.mcmAgentShiftStore, multiSelect: true, x: 0, y: 100, columns: [
{ xtype: 'gridcolumn', header: 'Name', width: 120, dataIndex: 'Name',
editor: {
xtype: 'textfield',
allowBlank: false
}
},
{ xtype: 'gridcolumn', header: 'Initials', width: 45, dataIndex: 'Initials',
editor: { xtype: 'textfield' }
},
{ xtype: 'gridcolumn', header: 'Employee Id', width: 75, dataIndex: 'EmployeeId',
editor: {
xtype: 'numberfield',
allowBlank: false
}
},
{ xtype: 'gridcolumn', header: 'Phone#', width: 100, dataIndex: 'MobilePhoneId',
editor: {
//TCS: 12/3/2013 cell phone table modified
xtype: 'combobox',
typeAhead: true,
editable: true,
triggerAction: 'all',
selectionOnTab: true,
// lazyRender: true,
// forceSelection: true,
store: App.mcmAllMobilePhoneStore,
displayField: 'MobileIdentifier',
valueField: 'MobilePhoneId',
value: 'MobilePhoneId',
queryMode: 'local',
queryDelay: 100,
specialkey: function(f, e) {
if(e.getKey() === e.ESC) {
this.hide(); }
},
listeners: {
load: function(store, recs, success) {
if(Ext.typeOf(this.getPicker().loadMask) != "boolean") {
console.log("trying to hide the loadmask");
this.getPicker().loadMask.hide();
}
}
}
},
> renderer: function(value,metaData,record) {
if(value) {
var MobileStore = Ext.getStore( App.mcmAllMobilePhoneStore);
var Record = MobileStore.findRecord('MobilePhoneId', value);
return Record ? Record.get('MobileIdentifier'): record.get('MobileIdentifier');
} else return "";
}//TCS: 12/3/2013 cell phone table modified end*/ },
{ xtype: 'datecolumn', header: 'Start Date', width: 84, dataIndex: 'StartAvailability', format: 'Y-m-d',
editor: {
xtype: 'datefield',
allowBlank: false,
format: 'Y-m-d'
}
},
{ header: 'Start', width: 65, dataIndex: 'StartAvailabilityTime', format: 'H:i',
editor: {
xtype: 'timefield',
id: starttime,
format: 'H:i',
increment: 15,
allowBlank: false
}
},
{ xtype: 'datecolumn', header: 'End Date', width: 84, dataIndex: 'EndAvailability', format: 'Y-m-d',
editor: {
xtype: 'datefield',
allowBlank: false,
format: 'Y-m-d'
}
},
{ header: 'End', width: 65, dataIndex: 'EndAvailabilityTime', format: 'H:i',
editor: {
xtype: 'timefield',
id: endtime,
format: 'H:i',
increment: 15,
allowBlank: false
}
} ], tbar: [
{
text: 'Add',
tooltip: 'Add Shift',
iconCls: 'icon-shift-add',
scope: me,
handler: function() {
var agent = this.mcmAgentCombobox.getValue();
if(agent) {
addShift.call(this, agent);
} else {
App.mcmShowMessageBox({
title: 'Important',
message: 'Please select an agent',
time: 2000
});
}
}
},
{
itemId: 'removeShift',
text: 'Remove',
tooltip: 'Remove Selected Shifts',
iconCls: 'icon-shift-remove',
scope: me,
handler: function() {
this.mcmRemoveShifts();
},
disabled: true
},
{
itemId: 'closeoutShift',
text: 'Closeout',
tooltip: 'Closeout Selected Shifts',
iconCls: 'icon-shift-closeout',
scope: me,
handler: function() {
var selection = this.mcmGridPanel.getSelectionModel().getSelection();
if(selection.length && selection.length > 1) {
App.mcmShowMessageBox({
title: 'Important',
message: 'Please enter a single shift to perform closeout',
time: 2000
});
return;
}
App.mcmCloseoutShift(selection[0]);
},
disabled: true
},
//TCS: 12/3/2013 cell phone table modification
{
text: 'Add Cell Phone',
tooltip: 'Add CellPhone',
iconCls: 'icon-cellphone-add',
scope: this,
handler: function()
{
this.hide;
App.mcmShowMobilePhoneWindow();
}
},
//TCS: 12/3/2013 cell phone table modification end ], plugins: [ this.mcmRowEditing ], viewConfig: {}, listeners: {
scope: me,
beforeedit : function(editor, e) {
editor.down('[#id=starttime]').clearValue();
editor.down('[#id=endtime]').clearValue();
} }
I reset the values before edit. but it not working.
I have a popup window with a combobox and a few buttons. The idea is to make a selection in the combobox and then either save the selection to a store or cancel. I have done this before and never had any problems, but with this code I get Uncaught TypeError: Cannot call method 'apply' of undefined whenever I try to interact with the combo. It seems to me like ExtJS is trying to run code meant for the store on the combobox.
I load the popup window with Ext.create('Account.Window.Reuse');
The definitions:
Ext.define('SimpleAccount', {
extend: 'Ext.data.Model',
idProperty: 'AccountID',
fields: [ {
name: 'AccountID',
type: 'int',
useNull: true
}, 'Name']
});
var userAccountReuseStore = Ext.create('Ext.data.Store', {
model: 'SimpleAccount',
storeId: 'userAccountReuseStore',
data: [{"AccountID":"1", "Name":"FirstAccount"},
{"AccountID":"2", "Name":"SecondAccount"},
{"AccountID":"3", "Name":"ThirdAccount"}]
});
Ext.define('Account.Reuse.ComboBox', {
extend: 'Ext.form.ComboBox',
alias: 'widget.accountReuseComboBox',
initComponent: function(){
Ext.apply(this, {
fieldLabel: 'Account',
displayField: 'Name',
valueField: 'AccountID',
queryMode: 'local'
})
}
});
Ext.define('Account.Reuse.Fieldset', {
extend: 'Ext.form.FieldSet',
alias: 'widget.accountReuseFieldset',
initComponent: function(){
Ext.apply(this, {
items: [
{
xtype: 'label',
cls: 'text-important',
margin: '0 0 10 0',
style: 'display: block',
text: 'Only attach an account you have permission to use. After attaching the account you will not be able to use, remove, or edit it until approved by SCSAM'
},
{
xtype: 'accountReuseComboBox',
store: userAccountReuseStore
}
]
});
this.callParent();
}
});
Ext.define('Account.Reuse.Details', {
extend: 'Ext.form.Panel',
alias: 'widget.accountReuseDetails',
initComponent: function(){
Ext.apply(this, {
plain: true,
border: 0,
bodyPadding: 5,
fieldDefaults: {
labelWidth: 55,
anchor: '100%'
},
layout: {
type: 'vbox',
align: 'stretch',
flex: 1
},
items: [
{
xtype: 'accountReuseFieldset',
defaults: {
labelWidth: 89,
anchor: '100%',
layout: {
type: 'vbox',
defaultMargins: {top: 0, right: 5, bottom: 0, left: 0},
align: 'stretch'
}
},
title: 'Details',
collapsible: false
}]
});
this.callParent();
}
});
Ext.define('Account.Window.Reuse', {
extend: 'Ext.window.Window',
alias: 'widget.accountWindowReuse',
initComponent: function(){
Ext.apply(this, {
title: 'Account Details',
width: 400,
autoShow: true,
modal: true,
layout: {
type: 'fit',
align: 'stretch' // Child items are stretched to full width
},
items: [{
xtype: 'accountReuseDetails',
id: 'attachAccountReuseForm'
}],
dockedItems: [{
xtype: 'toolbar',
dock: 'bottom',
ui: 'footer',
layout: {
pack: 'center'
},
items: [{
minWidth: 80,
text: 'Attach',
id: 'saveButton',
handler: function(){
var rec = this.up('accountWindowReuse').down('accountReuseDetails').getValues();
var store = Ext.getStore('userAccountReuseAttachStore');
store.add(rec);
this.up('window').close();
}
},{
minWidth: 80,
text: 'Cancel',
handler: function(){
this.up('window').close();
}
}]
}]
});
this.callParent();
}
});
It looks like you forget call parent in your Account.Reuse.ComboBox initComponent function so combobox is not initialized properly.
Your Account.Reuse.ComboBox initComponent function should look like this:
initComponent: function(){
Ext.apply(this, {
fieldLabel: 'Account',
displayField: 'Name',
valueField: 'AccountID',
queryMode: 'local'
});
this.callParent();
}