Create one or more textfield dynamically based on combobox selection - extjs

I am working on a front UI, a dropdown will be provided which will have the list of commands and one or two variables depending of command, what I am trying to do is when I select the command from dropdown, it should populate textfield where the user will provide the values.
e,g Command : "show route table <vrf_name> <ip_addr>"
then two new textfields should be created for user to fill in these values. I am stumped on how to create textfields with variable names. ?
var commands = Ext.create('Ext.data.Store', {
fields: ['command', 'reqvalues'],
data : [
{"command":"op find-security-zone ip <ip_addr>", "reqvalues":"ip_addr"},
{"command":"show configuration | display set | match <match_text>", "reqvalues":"match_text"},
{"command":"show route table <vrf_name> <ip_addr>", "reqvalues":"vrf_name, ip_addr"}
]
});
// Create the combo box, attached to the data store
Ext.create('Ext.form.ComboBox', {
fieldLabel: 'Select Command',
store: commands,
queryMode: 'local',
displayField: 'command',
valueField: 'command',
renderTo: Ext.getBody(),
});
Fiddle : https://fiddle.sencha.com/fiddle/3f2t

For dynamically adding fields, try the following code. It adds an initially empty fieldset, and when user selects something from the combobox, it adds textfields to the fieldset, after deleting all previously added textfields. (Instead of fieldset you can use container etc.)
This is a working fiddle.
var commands = Ext.create('Ext.data.Store', {
fields: ['command', 'reqvalues'],
data : [
{"command":"op find-security-zone ip <ip_addr>", "reqvalues":"ip_addr"},
{"command":"show configuration | display set | match <match_text>", "reqvalues":"match_text"},
{"command":"show route table <vrf_name> <ip_addr>", "reqvalues":"vrf_name, ip_addr"}
]
});
Ext.create('Ext.panel.Panel', {
renderTo: Ext.getBody(),
items: [{
xtype: 'combobox',
fieldLabel: 'Select Command',
store: commands,
queryMode: 'local',
displayField: 'command',
valueField: 'command',
listeners: {
// this is needed to remove all textfields when nothing is selected
change: function(combo, newValue, oldValue, eOpts) {
if (!newValue) {
// remove all existing textfields from fieldset
combo.up('panel').getComponent('parameters').removeAll();
}
},
select: function(combo, records, eOpts ) {
// get fieldSet
var fieldSet = combo.up('panel').getComponent('parameters');
// remove previous textfields
fieldSet.removeAll();
// get parameters from selection, assuming only 1 can
// be selected and delimiter in reqvalues is always ', '
var parameters = records[0].get('reqvalues').split(', ');
// loop through parameters and add textfield for each
Ext.Array.each(parameters, function(parameter) {
fieldSet.add({
xtype: 'textfield',
fieldLabel: parameter,
// by setting itemId, you can easily get textfield values,
// for example:
// fieldSet.getComponent('parameter_name')
itemId: parameter
})
});
}
}
}, {
// fieldSet for parameters, initially empty, can be container etc.
xtype: 'fieldset',
title: 'Parameters',
itemId: 'parameters'
}]
});

Better to use card layout with pre-defined forms and switch them using combobox. Something like this:
Ext.define('CommandsStore', {
extend: 'Ext.data.Store',
fields: ['command', 'cardIndex'],
data: [{
command: "op find-security-zone ip <ip_addr>",
cardIndex: 0
}, {
command: "show configuration | display set | match <match_text>",
cardIndex: 1
}, {
command: "show route table <vrf_name> <ip_addr>",
cardIndex: 2
}]
});
Ext.application({
name: 'Fiddle',
launch: function () {
Ext.create('Ext.panel.Panel', {
layout: 'card',
title: "Commands",
dockedItems: [{
xtype: 'toolbar',
items: [{
xtype: 'combobox',
fieldLabel: 'Select Command',
store: Ext.create('CommandsStore'),
queryMode: 'local',
displayField: 'command',
valueField: 'cardIndex',
width: 400,
value: 0,
listeners: {
select: function (combo, records) {
var cardIndex = records[0].get('cardIndex');
this.up('panel').getLayout().setActiveItem(cardIndex);
}
}
}]
}],
defaults: {
xtype: 'form',
layout: 'form',
bodyPadding: 5,
border: false,
},
items: [{
items: [{
xtype: 'textfield',
fieldLabel: "IP Address",
name: 'ip_addr'
}]
}, {
items: [{
xtype: 'textfield',
fieldLabel: "Match Text",
name: 'match_text'
}]
}, {
items: [{
xtype: 'textfield',
fieldLabel: "IP Address",
name: 'ip_addr'
}, {
xtype: 'textfield',
fieldLabel: "VRF Name",
name: 'vrf_name'
}]
}],
height: 400,
renderTo: Ext.getBody()
})
}
});

Related

Swapping two components in extjs

I have two components in my form which are "Source" and "Destination". And I want to give an option to change the order of those 2 components when clicked on "Swap" button.
Is this achievable in Extjs form ..?
https://fiddle.sencha.com/#view/editor&fiddle/3ej6
I attach here one possible solution: I removed both the fields and added them again with right indices.
listeners: {
click: function(){
const panel = this.up('panel');
const sourceForm = panel.query('combo[reference=source]');
const destinationForm = panel.query('combo[reference=destination]');
panel.remove(sourceForm)
panel.remove(destinationForm)
panel.insert(0, destinationForm)
panel.insert(1, sourceForm)
}
}
Here the link to working Fiddle.
---- EDIT -----
This is the new snippet to adapt the fiddle to your comment:
const panel = this.up('panel');
const sourceForm = panel.query('combo[reference=source]');
const destinationForm = panel.query('combo[reference=destination]');
const sourceIndex = panel.items.items.indexOf(sourceForm[0])
panel.remove(sourceForm)
panel.remove(destinationForm)
panel.insert(sourceIndex, destinationForm)
panel.insert(sourceIndex === 0 ? 1 : 0, sourceForm)
The working fiddle can be found at the same old link.
Different approach can be found here:
https://fiddle.sencha.com/#view/editor&fiddle/3em7
let combo1 = Ext.create({
xtype: 'combo',
name: 'source',
fieldLabel: 'source',
reference: 'source',
displayField: 'name',
valueField: 'abbr',
store: [{
abbr: 'AL',
name: 'Alabama'
}, {
abbr: 'AK',
name: 'Alaska'
}, {
abbr: 'AZ',
name: 'Arizona'
}, {
xtype: 'button',
}],
allowBlank: false // requires a non-empty value
})
let combo2 = Ext.create({
xtype: 'combo',
name: 'source1',
fieldLabel: 'dest',
reference: 'source1',
displayField: 'name',
valueField: 'abbr',
//hidden: true,
store: [{
abbr: 'AL',
name: 'Alabama'
}, {
abbr: 'AK',
name: 'Alaska'
}, {
abbr: 'AZ',
name: 'Arizona'
}, {
xtype: 'button',
}],
allowBlank: false // requires a non-empty value
})
let items = [combo1, combo2];
let wrapper = Ext.create({
xtype: 'container',
layout: 'vbox',
items: items
})
Ext.create('Ext.form.Panel', {
title: 'Contact Info',
width: 300,
bodyPadding: 10,
renderTo: Ext.getBody(),
items: [wrapper, {
xtype: 'button',
text: "Swap",
handler:(b)=> {
wrapper.removeAll(false);
wrapper.add(items.reverse());
}
}]
});
Technically, as far as i remember, items within a (container) component are managed using a mixed collection.
https://docs.sencha.com/extjs/6.5.3/classic/Ext.util.MixedCollection.html
You can try to change the order there and refresh the view.
I guess we missed the CSS only solution.
You can use ordinal-group to swap items. Just add a class, which adds a higher group number to the first combobox.
listeners: {
click: function () {
let view = this.up(),
sourceComp = view.down('combo[reference=source]');
sourceComp.toggleCls('box-reverse')
}
}
.box-reverse {
-webkit-box-ordinal-group: 3!important;
}
Here is your fiddle

Extjs textfield binding

I am trying to find the best way to bind items to a textfield in my extjs project. I downloaded the data into a store with one record in the controller. How would I bind to this textfield from the one record? I would preferably bind in the view, not in the controller
You should read this guide to understand better what binding is
The best solution for you is bind the record on the viewmodel of the view, so:
textfield.setBind({
value:'{myRec.valueToRefer}'
})
viewmodel.set('myRec',record.getData());
If you want, you can also use a form to handle this, using form.loadRecord and giving to the textfield a name..
A tip:
set inside the viewmodel a value to null:
data:{
myRec:null
}
Set your record in the viewmodel after setting the bind to the textfield.
Other tip:
If you can, avoid using setBind and prefer to set the binding directly on textfield creation:
//WILL WORK BUT YOU CAN AVOID IT
textfield.setBind({
value:'{myRec.valueToBind}'
})
//YES
var textfield=Ext.create({
xtype:'textfield',
bind:{
value:'{myRec.valueToBind}'
}
});
Refer to Sencha documentation also
You can use bind config to bind the data or any other config for ExtJS component.
Bind setting this config option adds or removes data bindings for other configs.
For example, to bind the title config:
var panel = Ext.create({
xtype: 'panel',
bind: {
title: 'Hello {user.name}'
}
});
To dynamically add bindings:
panel.setBind({
title: 'Greetings {user.name}!'
});
To remove bindings:
panel.setBind({
title: null
});
In this FIDDLE, I have created a demo for biding. I hope this will help/guide you to achieve you requirement.
CODE SNIPPET
Ext.application({
name: 'Fiddle',
launch: function () {
//defining Store
Ext.define('Store', {
extend: 'Ext.data.Store',
alias: 'store.gridstore',
autoLoad: true,
fields: ['name', 'email', 'phone'],
proxy: {
type: 'ajax',
url: 'data1.json',
reader: {
type: 'json',
rootProperty: ''
}
}
});
//defining view model
Ext.define('MyViewModel', {
extend: 'Ext.app.ViewModel',
alias: 'viewmodel.myvm',
data: {
formdata: null
},
stores: {
gridstore: {
type: 'gridstore'
}
}
});
//Controller
Ext.define('MyViewController', {
extend: 'Ext.app.ViewController',
alias: 'controller.myview',
onGridItemClick: function (grid, record) {
//Bind the form data for CLICKED record
this.getViewModel().set('formdata', record)
}
});
//creating panel with GRID and FORM
Ext.create({
xtype: 'panel',
controller: 'myview',
title: 'Binding Example',
renderTo: Ext.getBody(),
viewModel: {
type: 'myvm'
},
layout: 'vbox',
items: [{
xtype: 'grid',
flex: 1,
width: '100%',
bind: '{gridstore}',
columns: [{
text: 'Name',
dataIndex: 'name'
}, {
text: 'Email',
dataIndex: 'email',
flex: 1
}, {
text: 'Phone',
dataIndex: 'phone'
}],
listeners: {
itemclick: 'onGridItemClick'
}
}, {
xtype: 'form',
flex: 1,
width: '100%',
defaults: {
anchor: '100%'
},
title: 'Bind this form on Grid item Click',
bodyPadding:15,
margin: '20 0 0 0',
// The fields
defaultType: 'textfield',
items: [{
fieldLabel: 'Name',
name: 'first',
allowBlank: false,
bind: '{formdata.name}'
}, {
fieldLabel: 'Email',
name: 'email',
allowBlank: false,
bind: '{formdata.email}'
}, {
fieldLabel: 'Phone',
name: 'phone',
allowBlank: false,
bind: '{formdata.phone}'
}]
}]
});
}
});

Extjs checkbox shows always checked (second time onwards, within a dynamically added window modal (i.e if rendered within body only)

I have a users grid, on double click of users grid I am showing update user form in a window modal popup.
on dblClick of users grid I am adding user-detail-window
to mainView.
user-detail-window contains a user-detail form, which contains checkbox field called active
If user_abc is not active, then for the first time after opening update form for user_abc, its showing unchecked active field (this
is correct behavior, user_abc is already deactived)
If you open any other user record (which is active) and then again open user_abc (this is already deactivated), its shows active filed checked (instead of showing unchecked)
i) I have a checkbox field in user update form i.e. my UserDetail view
Ext.define('TestCMS.view.UserDetail', {
extend: 'Ext.form.Panel',
alias: 'widget.user-detail',
itemId: 'user-detail',
items: [
{
xtype: 'combobox',
name: 'locale',
fieldLabel: 'Taal',
store: 'i18n.Language',
displayField: 'iso639',
valueField: 'iso639',
autoLoad: true,
forceSelection: true,
editable: false,
triggerAction: 'all',
bind: '{currentText.locale}',
},
{
xtype: 'checkboxfield', //all fields in this form
name: 'active', //are showing proper data,
fieldLabel: 'Actief', //except this checkbox
bind: '{currentText.active}'
},
{
xtype: 'ckeditor',
fieldLabel: 'description',
itemId: 'ckeditor-body',
name: 'text',
bind: '{currentText.text}',
msgTarget: 'under',
CKConfig: {
extraPlugins: wordcount,notification',
}
}
});
ii) Following is MainView
Ext.define('TestCMS.view.UserMain', {
extend: 'Ext.container.Container',
alias: 'widget.user-main',
itemId: 'user-main',
layout: 'border',
defaults: {
split: true,
border: 0
},
viewModel: {
type: 'user-vm',
},
items: [
{
xtype: 'user-grid',
reference: 'user-grid',
region: 'west',
width: 350,
title: 'users',
multiSelect: false
}
});
iii) Following is detailWindowView
Ext.define('TestCMS.view.UserDetailWindow', {
extend: 'Ext.window.Window',
alias: 'widget.UserDetailWindow',
itemId: 'user-detail-window',
controller: 'user-detail',
requires: [
'TestCMS.controller.UserDetail',
],
layout: 'fit',
minHeight: 632,
minWidth: 1088,
closable: true,
modal: true,
closeAction: 'destroy',
maximizable: true,
bind: {
hidden: '{userDetailPanelDisabled}',
},
items: [
{
xtype: 'user-detail',
}
],
renderTo: Ext.getBody(), //This line causes the bug
});
I have added this line (i.e. renderTo: Ext.getBody()) to show Popup window on entire screen.
Without this line popup window is showing within a container only.
After adding only this line in above code, checkbox functionality related error occurred, otherwise it was working fine.
iv) Following is user gridview dblClick handler
onItemDblClick: function (view, record, item, index, e, eOpts) {
var userDetailWindow = Ext.widget('UserDetailWindow');
var mainView = view.up('#user-main');
viewModel = mainView.getViewModel();
mainView.add(userDetailWindow);
userDetailWindow.down('#user-detail').loadRecord(record);
contentWindow.show();
contentWindow.setTitle('user: ' + viewModel.data.userName);
},
Found solution after trying many different things
1) Removed Items[] from detailWindowView
items: [
{
xtype: 'user-detail',
}
],
2) Added user-detail runtime to user-detail-window
within onItemDblClick
mainView.add(userDetailWindow);
//added this line and problem solved
contentWindow.add(Ext.widget('user-detail'));
contentWindow.show();
contentWindow.setTitle('user: ' + viewModel.data.userName);

How to add selectable option to combobox without affecting the store on Sencha ExtJS 5?

so I have a view where I display a combobox and a grid that share a 'Roles' store. If you pick an option on the combobox, the grid will be filtered accordingly.
I am looking for a way to add an "All" option to the combobox that is selectable (so placeholder or value attributes don't work for me). I want to do this because I cannot add that option to the store without affecting the grid as well.
This is my code:
Ext.define("MODIFE.view.administration.Roles",{
extend: "Ext.panel.Panel",
xtype: "app-administration-roles",
controller: "administration-roles",
viewModel: {
type: "administration-users"
},
title: "Roles",
items:[
{
title: 'Búsqueda de Roles',
frame: true,
resizable: true,
xtype: 'form',
layout: 'column',
defaults: {
layout: 'form',
xtype: 'container',
defaultType: 'textfield',
style: 'width: 50%'
},
items: [{
items: [{
fieldLabel: 'Rol',
xtype: 'combobox',
store: 'Roles',
displayField: 'Description',
valueField: 'RoleId',
}]
}, {
items: [
{ fieldLabel: 'Estatus', xtype: 'combobox' },
]
}],
buttons: [
{ text: 'Nuevo' },
{ text: 'Buscar' }
]
},
{
layout: 'fit',
items: [{
xtype: 'grid',
id: 'rolesGrid',
title: 'Listado de Roles',
store: 'Roles',
columns: [
{ text: 'Rol', dataIndex: 'Description', flex: 2},
{ text: 'Estatus', dataIndex: 'Status', flex: 2},
]
}]
}]
});
Thanks in advance!
You could clone the store, then any alterations wont be reflected in the original store. (but it's messy, and may have problems with syncing if you have this enabled)
//clone store
var records = [],
me = this;
me.store.each(function(r){
records.push(r.copy());
});
var store2 = new Ext.data.Store({
recordType: me.store.recordType,
model: me.store.model
});
store2.add(records);
//add record
store2.add({ID:"-1", NAME: "-Please select-"});

extJS events/listeners for newb to js/extjs

I'm trying to learn a little bit about manipulating UI elements in forms. I have 2 graphical elements. I have a comboBox that has a list of arbitrary things and I have a very basic form panel.
what I'm trying to do is pass the contents of a clicked item in the combobox to the input box on the form.
Click on 'cat" in combobox then the form will say animal: cat ... I've been trying to add listeners and using the .on approaches to do this but I can't seem to get it. Any advice or hints would be much appreciated.
Ext.onReady(function () {
// The data store containing the list of cool stuffz
var animals = Ext.create('Ext.data.Store', {
fields: ['id', 'name'],
data: [{
"id": 'cat',
"name": "mycat"
}, {
'id' : 'dog',
"name": "mydog"
}, {
'id' : 'sbBarGirls',
"name": "heartbreaking-man-eating-deathclaw"
}
//...
]
});
// Create the combo box, attached to the states data store
Ext.create('Ext.form.ComboBox', {
id: 'combo',
width: 600,
fieldLabel: 'Choose animal',
emptyText: 'dont select the last one',
store: animals,
queryMode: 'local',
displayField: 'name',
valueField: 'id',
renderTo: Ext.getBody()
});
});
//non related code here..
Ext.onReady(function(){
Ext.create('Ext.form.Panel', {
title: 'Animal sanctuary, one animal per location ',
width: 300,
bodyPadding: 10,
style: 'background-color: #Fdd;',
renderTo: Ext.getBody(),
items: [{
xtype: 'textfield',
fieldLabel: 'animal:',
name: 'myanimal'
}]
});
});
what i was trying to do was use the dom event mousedown on one of the comboselections trigger a listener but i couldn't seem to get it to work, my apologies if the event/listener tags are incorrect.
So you need describe id for the text field, e.g.:
{
id: 'wild_but_very_good_animal',
xtype: 'textfield',
fieldLabel: 'animal:',
name: 'myanimal'
}
And add listener for the combo:
Ext.create('Ext.form.ComboBox', {
id: 'combo',
width: 600,
fieldLabel: 'Choose animal',
emptyText: 'dont select the last one',
store: animals,
queryMode: 'local',
displayField: 'name',
valueField: 'id',
renderTo: Ext.getBody(),
listeners: {
'change': function(field, selectedValue) {
Ext.getCmp('wild_but_very_good_animal').setValue(selectedValue);
}
}
});

Resources