I have the following code in ExtJS
var formPanel = Ext.create('Ext.form.Panel', {
title: 'Panel title',
renderTo: Ext.getBody(),
items: [{
xtype: 'container',
layout: 'hbox',
items: [{
xtype: 'textfield',
fieldLabel: 'First Name',
name: 'FirstName',
}, {
xtype: 'textfield',
fieldLabel: 'Last Name',
name: 'LastName',
},{
xtype:'fieldset',
title: 'Phone Number',
defaultType: 'textfield',
items :[{
fieldLabel: 'Home',
name: 'home',
value: '(888) 555-1212'
},{
fieldLabel: 'Business',
name: 'business',
toBeRendered: IS_BUSINESS_FIELD_SUPPORTED_IN_CURRENT_RELEASE // custom property that must restrict rendering
rendered: IS_BUSINESS_FIELD_SUPPORTED_IN_CURRENT_RELEASE //doesn't work
}]
}]
}]
});
I want to create an application, that will have properties file where I can set up flags for SUPPORTED fields e.g IS_BUSINESS_FIELD_SUPPORTED_IN_CURRENT_RELEASE = false. If it's false than text input fieldLabel: 'Business' will not be rendered at all - no hidden/disabled text input Business in html.
I've tried rendered property - but it doesn't work, the only solution so far is to use items = Ext.Array.filter(items,filterFunction) in onRender;
Are there any other solutions how can I restrict rendering input elements?
Thanks in advance.
Instead of the constructor, use the initItems method:
Ext.define('MyComponent', {
extend: 'Ext.panel.Panel',
xtype: 'mycomponent',
bodyPadding: 10,
border: true,
title: 'My component',
items : [
{
xtype: 'button',
text: 'My allowed button'
}
],
initItems : function() {
var items = this.items;
// Your conditions
if (false) {
items.push({
xtype: 'button',
text: 'My denied button'
});
}
this.callParent();
}
});
https://fiddle.sencha.com/#fiddle/17qi
I think that best approach is to define custom components for your application parts and add required components within its constructor, like this:
constructor: function () {
var myComponentItems = [
{
xtype: 'button',
text: 'My allowed button'
}
];
// Your conditions
if(false) {
myComponentItems.push({
xtype: 'button',
text: 'My denied button'
});
}
Ext.apply(this, {
items: myComponentItems
});
this.callParent(arguments);
}
Working fiddle
Related
I need to change xtype from textfield to textareafield basing on a condition.
I need to do something like this, but I cant update xtype
Ext.define('app',{
launch: function(){
var i = 1;
if (i == 1) {
Ext.getCmp('myID').updateXtype('textareafield')
}
},
items:[{
xtype: 'fieldset',
title: 'title'
},
items: [{
xtype: 'textfield',
label: 'label'
}]]
})
or i can use the viewmodel, but xtype is not bindable
Ext.define('app',{
launch: function(){
var i = 1;
if (i == 1) {
this.getViewModel().set('newXtype', 'textareafield');
}
},
items:[{
xtype: 'fieldset',
title: 'title'
},
items: [{
xtype: 'textfield',
label: 'label',
bind: {
xtype: '{newXtype}'
}
}]]
})
Exactly: you cannot bind xtype in this way. In the situation I would use a hidden binding . You will build the form with textfield and textareafield. Then switch the hidden binding depending on your use case (condition).
https://fiddle.sencha.com/#view/editor&fiddle/2trf
Ext.create('Ext.form.Panel', {
title: 'Switch between textfield and textareafield',
width: 360,
bodyPadding: 10,
renderTo: Ext.getBody(),
viewModel: {
data: {
showTextfield: true
}
},
defaults: {labelWidth: 120},
tbar: [{
text: 'Switch',
handler: function(button) {
let vm = this.up('panel').getViewModel();
let showTextfield = vm.get('showTextfield');
vm.set('showTextfield', !showTextfield)
}
}],
items: [{
xtype: 'textfield',
fieldLabel: 'TEXTFIELD',
bind: { hidden: '{showTextfield}'}
},{
xtype: 'textareafield',
fieldLabel: 'TEXTAREAFIELD',
bind: { hidden: '{!showTextfield}'}
}]
});
I'm trying to follow the tutorial of extjs about adding a form on click.
Now the "twist" is that I directly wish to create a more structured approach. So I'm using Ext.define to create both a grid and a form, for the grid.
The grid:
Ext.define('MyApp.view.main.EmployeeGrid', {
extend: 'Ext.grid.Grid',
xtype: 'employee-grid',
title: 'Employee Directory',
iconCls: 'x-fa fa-users',
listeners: {
itemtap: function() {
console.log("test");
Ext.create("MyApp.view.main.FormPanel", {});
}
},
store: {
data: [{
"firstName": "Jean",
"lastName": "Grey",
"phoneNumber": "(372) 792-6728"
}]
},
columns: [{
text: 'First Name',
dataIndex: 'firstName',
flex: 1
}, {
text: 'Last Name',
dataIndex: 'lastName',
flex: 1
}, {
text: 'Phone Number',
dataIndex: 'phoneNumber',
flex: 1
}]
});
the form:
Ext.define("MyApp.view.main.FormPanel", {
extend: "Ext.form.Panel",
xtype: 'form-panel',
title: 'Update Record',
floating: true,
centered: true,
width: 300,
modal: true,
items: [{
xtype: 'textfield',
name: 'firstname',
label: 'First Name'
}, {
xtype: 'toolbar',
docked: 'bottom',
items: ['->', {
xtype: 'button',
text: 'Submit',
iconCls: 'x-fa fa-check',
handler: function() {
this.up('formpanel').destroy();
}
}, {
xtype: 'button',
text: 'Cancel',
iconCls: 'x-fa fa-close',
handler: function() {
this.up('formpanel').destroy();
}
}]
}]
});
The problematic code is under the listeners: ... in the MyApp.view.main.EmployeeGrid class. The console is entry is logged, so I know the function is executed. However no form is shown. - What is the correct approach here?
Yes, as you said, no form is shown, because a newly created form is not shown by default.
Two solutions:
You can add to the form autoShow: true OR
You can add execute the show function on the created form: Ext.create(...).show()
However, I would recommend that you reuse the form, so instantiate a new one only once, store it on your grid, and reuse it for subsequent calls:
itemtap: function(view, index, target, record) {
if(!this.myForm) this.myForm = Ext.create("Ext.form.Panel", {});
this.myForm.loadRecord(record);
this.myForm.show();
}
For this to work, you may have to set closeAction: 'hide' on the form.
In at least some versions of ExtJS 6, it seemed to me as if IE exhibited memory leaks on component instantiation, so one should create as few new components as possible.
Currently I'm working on a code migration from ExtJS 4.2 to ExtJS 5.1. And I noticed MANY changes on default behavior of many components.
One of the things I noticed is that the default tab key navigation between components has changed and in this case is not quite predictable.
To reproduce go to the 4.2 fiddle here, and then click on the first text field, hit tab and then it would change focus to state combo box; hit tab again and it would go to "Next" button, hit tab again and it would go to "Second option" radio button, and so on in a predictable order.
Then repeat the same thing on 5.1 fiddle here. First thing you'll notice is that "My First Option" radio is unchecked (that's another issue), but the main issue I would like to fix is the odd order it follows on tab key press.
How can I make tab key navigation behave as it did on 4.2 version?
Including sample code here:
// The data store containing the list of states
var states = Ext.create('Ext.data.Store', {
fields: ['abbr', 'name'],
data : [
{"abbr":"AL", "name":"Alabama"},
{"abbr":"AK", "name":"Alaska"},
{"abbr":"AZ", "name":"Arizona"}
]
});
Ext.application({
name : 'Fiddle',
launch : function() {
Ext.create('Ext.form.Panel', {
title: 'My Navigable Panel',
items: [
{
xtype: 'radiogroup',
layout: 'vbox',
items: [
{
xtype: 'radiofield',
boxLabel: 'My First Option',
name: 'radio',
value: true,
checked: true,
listeners: {
change: function(group, newValue, oldValue) {
if(newValue) {
group.up('form').down('fieldcontainer[name=containerA]').show();
group.up('form').down('fieldcontainer[name=containerB]').hide();
} else {
group.up('form').down('fieldcontainer[name=containerA]').hide();
group.up('form').down('fieldcontainer[name=containerB]').show();
}
}
},
},
{
xtype: 'fieldcontainer',
layout: 'hbox',
name: 'containerA',
fieldDefaults: {
labelAlign: 'top',
margin: '0 5 0 5'
},
items: [
{
xtype: 'textfield',
fieldLabel: 'First field',
allowBlank: false
},
{
xtype: 'combo',
fieldLabel: 'State',
width: 50,
store : states,
queryMode: 'local',
displayField: 'name',
valueField: 'abbr',
},
{
xtype: 'button',
text: 'Next'
}
]
},
{
xtype: 'radiofield',
boxLabel: 'My Second Option',
name: 'radio',
value: false
}
]
},
{
xtype: 'fieldcontainer',
padding: '0 0 0 25',
name: 'containerB',
hidden: true,
items: [{
xtype: 'radiogroup',
layout: 'vbox',
items: [
{
xtype: 'radiofield',
fieldLabel: 'My nested radio button A',
name: 'subradio'
},
{
xtype: 'radiofield',
fieldLabel: 'My nested radio button B',
name: 'subradio'
}
]
}]
}
],
renderTo: Ext.getBody()
}).show();
}
});
Well, I did not find a way to tell ExtJS 5.1 to navigate through the form as it did on 4.2, but I managed to get the desired behavior by modifying my form composition (although it looks the same) in a way that ExtJS 5.1 was able to orderly follow.
To make that happen I removed the radiogroup component but kept all that was inside of it (which was pretty much the whole form content). It seems that structure didn't feel quite natural to the updated framework.
Here is a fiddle with the mentioned changes.
Including code here:
// The data store containing the list of states
var states = Ext.create('Ext.data.Store', {
fields: ['abbr', 'name'],
data : [
{"abbr":"AL", "name":"Alabama"},
{"abbr":"AK", "name":"Alaska"},
{"abbr":"AZ", "name":"Arizona"}
]
});
Ext.application({
name : 'Fiddle',
launch : function() {
Ext.create('Ext.form.Panel', {
title: 'My Navigable Panel',
items: [
{
xtype: 'radiofield',
boxLabel: 'My First Option',
name: 'radio',
value: true,
checked: true,
listeners: {
change: function(group, newValue, oldValue) {
if(newValue) {
group.up('form').down('fieldcontainer[name=containerA]').show();
group.up('form').down('fieldcontainer[name=containerB]').hide();
} else {
group.up('form').down('fieldcontainer[name=containerA]').hide();
group.up('form').down('fieldcontainer[name=containerB]').show();
}
}
},
},
{
xtype: 'fieldcontainer',
layout: 'hbox',
name: 'containerA',
fieldDefaults: {
labelAlign: 'top',
margin: '0 5 0 5'
},
items: [
{
xtype: 'textfield',
fieldLabel: 'First field',
allowBlank: false
},
{
xtype: 'combo',
fieldLabel: 'State',
width: 50,
store : states,
queryMode: 'local',
displayField: 'name',
valueField: 'abbr',
},
{
xtype: 'button',
text: 'Next'
}
]
},
{
xtype: 'radiofield',
boxLabel: 'My Second Option',
name: 'radio',
value: false
},
{
xtype: 'fieldcontainer',
padding: '0 0 0 25',
name: 'containerB',
hidden: true,
items: [{
xtype: 'radiogroup',
layout: 'vbox',
items: [
{
xtype: 'radiofield',
fieldLabel: 'My nested radio button A',
name: 'subradio'
},
{
xtype: 'radiofield',
fieldLabel: 'My nested radio button B',
name: 'subradio'
}
]
}]
}
],
renderTo: Ext.getBody()
}).show();
}
});
I am currently working with ExtJS. I have a textfield which has an emptyText set as a config.
"emptyText : 'Please enter'"
When I click on it, it doesn't disappear. Only if I enter something, it goes. Is there any way in which this can be done?
I don't really like this solution, but I've come up with this (viewable here):
Ext.application({
name : 'Fiddle',
launch : function() {
Ext.create('Ext.form.Panel', {
title: 'Contact Info',
width: 300,
bodyPadding: 10,
renderTo: Ext.getBody(),
items: [{
xtype: 'textfield',
name: 'name',
fieldLabel: 'Name',
allowBlank: false, // requires a non-empty value,
emptyText: 'blah',
originalEmptyText: 'blah',
listeners: {
focus: function() {
this.emptyText = ' '; // if you set it to empty string, it doesn't work
this.applyEmptyText();
},
blur: function() {
this.emptyText = this.originalEmptyText;
this.applyEmptyText();
}
}
}]
});
}
});
It should work for xtype:'textfield'. Can you provide more details about your attempt?
I did not get any issue.
Here is the sample code.
var form = new Ext.form.FormPanel({
items: [{
name: 'Test',
xtype:'textfield',
emptyText:'Empty Text',
}]
});
I'm trying to read a property from my custom panel for using it into a property item from the same panel. Let me show my code so you can understand what I mean:
Ext.define('XXX.XXX.XXX.MyPanel', {
extend: 'Ext.panel.Panel',
title: 'My Panel',
autoScroll: true,
isMyProperty: false,
defaults: {
margin: 4,
xtype: 'horizontalfieldpanel'
},
items: [
{
title: 'SOme title',
itemId: 'title1',
items: [
{
xtype: 'textfield',
name: 'name',
fieldLabel: 'Name',
allowBlank: !this.isMyProperty
}, {
xtype: 'textfield',
name: 'lastName',
fieldLabel: 'Last Name',
allowBlank: !this.isMyProperty
}, {
As you can see I have isMyProperty and I'm trying to use it on allowBlank, but it is not taking it. it is taking the value for default.
Any idea what I'm doing wrong?
Thanks,
The conventional way is to use the 'config' subsystem. This tells it to add a new configuration option to your class which also generates a getter/setter method for it.
The configuration option can be overridden when the panel is constructed just like any other config option in the base class.
One trick is that your items must then be constructed in the initComponent method as opposed to doing it in the class definition. I've found that in sophisticated applications, it's better to plan on overriding initComponent to create your items instead of using "static" item declarations in most situations.
Ext.define('XXX.XXX.XXX.MyPanel', {
extend: 'Ext.panel.Panel',
config: {
isMyProperty: false
},
title: 'My Panel',
autoScroll: true,
defaults: {
margin: 4,
xtype: 'horizontalfieldpanel'
},
initComponent: function() {
this.items = [{
title: 'Some title',
itemId: 'title1',
items: [{
xtype: 'textfield',
name: 'name',
fieldLabel: 'Name',
allowBlank: !this.#getIsMyProperty()
}, {
xtype: 'textfield',
name: 'lastName',
fieldLabel: 'Last Name',
allowBlank: !this.#getIsMyProperty()
}, {
...
}]
}];
this.callParent(arguments);
}
});
To override the value at construction:
var panel = Ext.create('XXX.XXXX.XXXX.MyPanel', {
isMyProperty: true
});