Swapping two components in extjs - 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

Related

Ext JS 6.5 - modern grid disabled not working

I am working on Ext JS 6.5 modern. I have some condition to disable the grid component, user has only rights to view the grid no one else.
I have tried disabled config and disable method but not working. Here is my Fiddle.
Code snippet
Ext.application({
name: 'Fiddle',
launch: function () {
Ext.create('Ext.data.Store', {
storeId: 'gridStore',
fields: ['name'],
data: [{
name: 'Test 1'
}, {
name: 'Test 2'
}, {
name: 'Test 3'
}, {
name: 'Test 4'
}]
});
Ext.create({
xtype: 'grid',
layout: 'fit',
fullscreen: true,
title: 'Baisc grid example',
store: 'gridStore',
//Here I have put {disabled: true} but not working
disabled: true,
columns: [{
text: 'Name',
flex: 1,
dataIndex: 'name'
}],
listeners: {
childtap: function (grid, location, eOpts) {
alert('childtap');
}
},
items: [{
xtype: 'toolbar',
items: {
xtype: 'button',
ui: 'action',
text: 'Disabled grid',
iconCls: 'x-fa fa-ban',
handler: function () {
//IT is also not working
this.up('grid').setDisabled(true);
this.up('grid').disable();
}
}
}]
//renderTo:Ext.getBody()
});
}
});
Somebody please help me with a solution for disabling the grid component.
As a workaround we can use grid.setMasked(true);
Here is the example Fiddle.
Another approach is to set grid's hideMode to opacity and then set it to hidden (this.up('grid').setHidden(true);).
For Example (editing your fiddle)
Ext.create('Ext.data.Store', {
storeId: 'gridStore',
fields: ['name'],
data: [{
name: 'Test 1'
}, {
name: 'Test 2'
}, {
name: 'Test 3'
}, {
name: 'Test 4'
}]
});
Ext.create({
xtype: 'grid',
layout: 'fit',
fullscreen: true,
title: 'Baisc grid example',
store: 'gridStore',
//Here I have put {disabled: true} but not working
//disabled: true,
hideMode: 'opacity',
columns: [{
text: 'Name',
flex: 1,
dataIndex: 'name'
}],
listeners: {
childtap: function (grid, location, eOpts) {
alert('childtap');
}
},
items: [{
xtype: 'toolbar',
items: {
xtype: 'button',
ui: 'action',
text: 'Disabled grid',
iconCls: 'x-fa fa-ban',
handler: function () {
this.up('grid').setHidden(true);
}
}
}]
//renderTo:Ext.getBody()
});
Also you need this css override:
<style>
.x-hidden-opacity {
opacity: 0.2 !important; //default is 0
pointer-events: none;
}
</style>

extjs6 modern card layut

I am new in Extjs. I have a container with card layout with 3 sub views including a grid, a form for creating and a form for updating using route.
items: [
{xtype: 'feature-grid',id:'feature-grid},
{xtype: 'create-form'},
{xtype: 'update-form'}
],
it works well at the first time but when I change the route and switch to this route again this error appears:
Uncaught Error: DOM element with id feature-grid in Element cache is not the same as element in the DOM. Make sure to clean up Element instances using destroy()
and when I remove the id the save button in my create form doesnt add record to the grid without any error!
my save button is like this:
var form = button.up('formpanel');
var values = form.getValues();
var user = Ext.create('App.model.User',values);
var cntr = this.getView('UserContainer')
var mainpanel = button.up('user-container');
var grid = mainpanel.down('grid');
grid.store.add(user);
form.reset();
this.redirectTo('users')
any idea?
As you are using routes so in this case first you need to check you view is already created or not. If view is already created then you can use that view otherwise you can create view.
In this FIDDLE, I have create a demo using cardlayout, grid and form. I hope this will help/guide you to achieve your requirement.
CODE SNIPPET
Ext.application({
name: 'Fiddle',
launch: function () {
//Define cotroller
Ext.define('MainController', {
extend: 'Ext.app.ViewController',
alias: 'controller.maincontroller',
routes: {
'application/:node': 'onViewChange'
},
//this event will fire whenver routing will be changed
onViewChange: function (xtype) {
var view = this.getView(),
newNode = view.down(xtype);
//if view is not crated then 1st created
if (!newNode) {
newNode = Ext.create({
xtype: xtype
});
}
// is new view is form then first reset the form
if (newNode.isXType('form')) {
newNode.reset();
}
// if new view type is update-form then load the record
if (xtype == 'update-form') {
newNode.setRecord(this.record)
this.record = null;
}
//If view is created then directly set active that view
view.setActiveItem(newNode);
},
//this event will fire when main view render
onMainViewAfterRedner: function () {
this.redirectTo('application/feature-grid');
},
//this event will fire when grid items clicked
onGridItemClick: function (grid, index, target, record, e, eOpts) {
this.record = record;
this.redirectTo('application/update-form');
},
//this event will fire when cancel button clicked
onCancelButtonClick: function () {
this.redirectTo('application/feature-grid');
},
//this event will fire when add new button clicked
onAddNew: function () {
this.redirectTo('application/create-form');
},
//this event will fire when save button clicked
onSaveButtonClick: function (button) {
var me = this,
form = button.up('formpanel'),
store = me.getView().down('grid').getStore(),
values = form.getValues();
if (form.xtype == 'update-form') {
store.findRecord('id', values.id).set(values);
} else {
if (values.name && values.email && values.phone) {
delete values.id;
store.add(values);
} else {
Ext.Msg.alert('Info','Please enter form details');
return false;
}
}
this.onCancelButtonClick();
}
});
Ext.define('AppForm', {
extend: 'Ext.form.Panel',
layout: 'vbox',
bodyPadding: 10,
defaults: {
xtype: 'textfield',
//flex: 1,
width: '100%',
margin: '10 5',
labelAlign: 'top',
allowBlank: false
},
items: [{
name: 'id',
hidden: true
}, {
name: 'name',
label: 'Name'
}, {
name: 'email',
label: 'Email'
}, {
name: 'phone',
label: 'Phone Number'
}, {
xtype: 'toolbar',
defaults: {
xtype: 'button',
ui: 'action',
margin: 5,
flex: 1
},
items: [{
text: 'Save',
formBind: true,
handler: 'onSaveButtonClick'
}, {
text: 'Cancel',
handler: 'onCancelButtonClick'
}]
}]
});
//this create-form.
Ext.define('CreateForm', {
extend: 'AppForm',
alias: 'widget.create-form',
title: 'Create form'
});
//this update-form.
Ext.define('UpdateForm', {
extend: 'AppForm',
alias: 'widget.update-form',
title: 'Update form'
});
//this feature-grid.
Ext.define('fGrid', {
extend: 'Ext.panel.Panel',
alias: 'widget.feature-grid',
title: 'User List grid',
layout: 'vbox',
items: [{
xtype: 'grid',
flex: 1,
store: {
fields: ['name', 'email', 'phone'],
data: [{
name: 'Lisa',
email: 'lisa#simpsons.com',
phone: '555-111-1224'
}, {
name: 'Bart',
email: 'bart#simpsons.com',
phone: '555-222-1234'
}, {
name: 'Homer',
email: 'homer#simpsons.com',
phone: '555-222-1244'
}, {
name: 'Marge',
email: 'marge#simpsons.com',
phone: '555-222-1254'
}]
},
columns: [{
text: 'Name',
dataIndex: 'name',
flex: 1
}, {
text: 'Email',
dataIndex: 'email',
flex: 1
}, {
text: 'Phone',
dataIndex: 'phone',
flex: 1
}],
listeners: {
itemtap: 'onGridItemClick'
}
}],
tools: [{
type: 'plus',
iconCls: 'x-fa fa-plus',
handler: 'onAddNew'
}],
flex: 1
});
//Define the main view form extending panel
Ext.define('MainView', {
extend: 'Ext.panel.Panel',
controller: 'maincontroller',
alias: 'widget.mainview',
layout: 'card',
listeners: {
painted: 'onMainViewAfterRedner'
}
});
//this will create main view that is card layout
Ext.create({
xtype: 'mainview',
renderTo: Ext.getBody(),
fullscreen: true
});
}
});

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 - Column Editor with different xtype based on record value

I have a gridpanel with rowediting plugin enabled. I was wondering if it is possible to display in the same cell either checkbox control or numberfield based on data that's being returned from server. I have not seen anything like that before and googling has not yield any results so it may be impossible at all. It looks like I have to specify different editor types not per each column but per each cell.
How can I achieve that?
P.S. I must have a chance to edit that cell, i.e. change number value or check/uncheck checkbox.
That is very easy to achieve, you will need to use the getEditor method of your grid column and get it to return the form field you want:
Example:
{
xtype: 'gridcolumn',
getEditor: function(record) {
var grid = this.up('grid'),
cellediting = grid.findPlugin('cellediting'),
editors = cellediting.editors,
editor = editors.getByKey(this.id),
fieldType;
if (editor) {
// Do this to avoid memory leaks
editors.remove(editor);
}
fieldType = isNaN(parseFloat(record.get('salary'))) ? 'textfield' : 'numberfield';
return {
xtype: fieldType,
allowBlank: false
};
},
dataIndex: 'salary',
text: 'Salary',
flex: 1
}
I have created a fiddle demonstrating the use of this method, if the column Salary holds a string it will edit with a textfield, if it holds a number, it will edit with a Numberfield.
Hope it helps
Fiddle: https://fiddle.sencha.com/#fiddle/c2m
My fiddle is working with the CellEditor plugin, you will have to make the adjustments to make it work with your RowEditor plugin, for further reference, check the documentation for Grid Column and the getEditor method.
Many thanks to Guilherme Lopes for the nice code to begin with. Here is the sample of what I finally got:
var data = [{
name: 'Richard Wallace',
age: 24,
hired: '9/21/2013',
active: true,
salary: 1,
checkbox: true
}, {
name: 'Phyllis Diaz',
age: 29,
hired: '1/27/2009',
active: false,
salary: 41244,
checkbox: false
}, {
name: 'Kathryn Kelley',
age: 23,
hired: '9/14/2011',
active: false,
salary: 98599.9,
checkbox: false
}, {
name: 'Annie Willis',
age: 36,
hired: '4/11/2011',
active: true,
salary: 0,
checkbox: true
}];
var store = Ext.create('Ext.data.Store', {
data: data,
fields: [{
name: 'name'
}, {
type: 'float',
name: 'age'
}, {
type: 'date',
name: 'hired'
}, {
type: 'boolean',
name: 'active'
}, {
name: 'salary'
}]
});
Ext.define('MyApp.view.MyGridPanel', {
extend: 'Ext.grid.Panel',
alias: 'widget.mygridpanel',
height: 315,
width: 784,
title: 'Employees',
store: store,
viewConfig: {
listeners: {
beforecellclick: function (view, cell, cellIndex, record, row, rowIndex, e) {
if (cellIndex == 4 && record.get('checkbox')) {
if (record.get('salary')) {
record.set('salary', 0);
} else {
record.set('salary', 1);
}
return false;
}
return true;
}
}
},
columns: [{
xtype: 'gridcolumn',
dataIndex: 'name',
text: 'Name',
flex: 1,
editor: {
xtype: 'textfield'
}
}, {
xtype: 'gridcolumn',
dataIndex: 'age',
text: 'Age'
}, {
xtype: 'datecolumn',
dataIndex: 'hired',
text: 'Hired',
flex: 1
}, {
xtype: 'checkcolumn',
dataIndex: 'active',
text: 'Active'
}, {
xtype: 'gridcolumn',
getEditor: function (record) {
var fieldType = record.get('checkbox') ? 'checkboxfield' : 'textfield';
return Ext.create('Ext.grid.CellEditor', {
field: {
xtype: fieldType,
allowBlank: false
}
});
},
renderer: function (value, metaData) {
if (metaData.record.get('checkbox')) {
if (metaData.record.get('salary')) {
return '<div style="text-align: center"><img class="x-grid-checkcolumn x-grid-checkcolumn-checked" src="data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw=="></div>';
} else {
return '<div style="text-align: center"><img class="x-grid-checkcolumn" src="data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw=="></div>';
}
}
return value;
},
dataIndex: 'salary',
text: 'Salary',
flex: 1
}],
plugins: [{
ptype: 'cellediting',
autoCancel: false,
clicksToEdit: 1
}]
});
Ext.create('MyApp.view.MyGridPanel', {
renderTo: Ext.getBody()
});
Working example on Sencha's fiddle https://fiddle.sencha.com/#fiddle/c3p
Editor contains one field, and this editor is used for the whole column. You can't specify two xtypes or multiple editors for one column.
That said, it is not completely impossible, but it will require some work.
You will have to define a new custom field with custom xtype.
Tell this field to either render a checkboxfield or a numberfield, depending on the value.
This will require you to override/implement most if not all functions that a Ext.form.field.Base has...

ExtJs getValues() from Form

i have a question.
probably it will be a easy solution.
how can i get the Values of the textfields, when i click the Save Button???
Ext.define('MyApp.view.main.MyForm', {
extend: 'Ext.Window',
layout: 'column',
.
.
.
defaults: {
layout: 'form',
xtype: 'container',
defaultType: 'textfield',
labelWidth: 150,
width: 300
},
items: [{
items: [
{ fieldLabel: 'FirstName', allowBlank: false },
{ fieldLabel: 'LastName', allowBlank: false },
]
}, {
items: [
{ fieldLabel: 'Street' },
{ fieldLabel: 'Town' },
]
}],
buttons: [
{ text: 'Save', handler: function(){ alert('Saved!'); } },
]
});
You must use form field container, for example - Ext.form.Panel.
Then you can use getForm() and then getValues(), also check your fields - isValid() for checking allowBlank.
var formPanel = Ext.create('Ext.form.Panel', {
name: 'myfieldform',
defaults: {
layout: 'form',
xtype: 'container',
defaultType: 'textfield',
labelWidth: 150,
width: 300
},
items: [{
items: [
{
fieldLabel: 'FirstName',
allowBlank: false
},
{
fieldLabel: 'LastName',
allowBlank: false
},
]
}, {
items: [
{ fieldLabel: 'Street' },
{ fieldLabel: 'Town' },
]
}]
});
Ext.define('MyApp.view.main.MyForm', {
...
items: [
formPanel
],
buttons: [
{
text: 'Save',
handler: function(btn) {
var form = btn.up().up().down('[name="myfieldform"]').getForm(),
values;
if (!form || !form.isValid())
{
alert('Check your form please!');
return;
}
values = form.getValues();
for(var name in values) {
alert(values[name]);
}
}
}
]
});
Sencha Fiddle Example
Your handler function will have the button and the event options in it's signature. Use the button and the "Up" function to get the form element and retrieve the record model attached to the form (assuming you are using models).
handler: function(btn, eOpts){
var form = btn.up('form');
form.getForm().updateRecord();
var record = form.getForm().getRecord();
alert('Saved!');
}
If you are not using a model and just want the values add an itemId to each field in your form and again use the up function with a "#" to retrieve a specific component. Then simply use the getValue method.
items: [
{ fieldLabel: 'FirstName', itemId: 'firstnamefield', allowBlank: false },
{ fieldLabel: 'LastName', itemId: 'lastnamefield', allowBlank: false },
]
handler: function(btn, eOpts){
var firstNameField = btn.up('#firstnamefield');
var firstNameValue = firstNameField.getValue();
alert('Saved!');
}
Seriously, why go with the up.up.down approach, if you can get to the thing straight away?
var form = Ext.ComponentQuery.query('[name="myfieldform"]').getForm()[0];
Or
values = Ext.ComponentQuery.query('[name="myfieldform"]').getForm()[0].getValues();
In other words, take above answer and make it like this:
var formPanel = Ext.create('Ext.form.Panel', {
name: 'myfieldform',
defaults: {
layout: 'form',
xtype: 'container',
defaultType: 'textfield',
labelWidth: 150,
width: 300
},
items: [{
items: [
{
fieldLabel: 'FirstName',
allowBlank: false
},
{
fieldLabel: 'LastName',
allowBlank: false
},
]
}, {
items: [
{ fieldLabel: 'Street' },
{ fieldLabel: 'Town' },
]
}]
});
Ext.define('MyApp.view.main.MyForm', {
...
items: [
formPanel
],
buttons: [
{
text: 'Save',
handler: function(btn) {
var form = Ext.ComponentQuery.query('[name="myfieldform"]').getForm()[0];
if (!form || !form.isValid())
{
alert('Check your form please!');
return;
}
values = form.getValues();
for(var name in values) {
alert(values[name]);
}
}
}
]
});

Resources