ExtJS - reading a property from a custom panel - javascript

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
});

Related

Change textfield to textareafield

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}'}
}]
});

Sencha ext.js, create form on the fly

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.

ExtJS conditionally render input fields

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

How to fix default tab key navigation in Extjs 5.1?

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();
}
});

Sencha Touch 2: Reloading a treeStore in nestedList to reflect user selection

I have a nested list in my application, and when users make a selection they are taken to a detailCard with some options. One of these options is to "confirm" their selection. Once confirmed, the selection should be removed from the list. This works on the server side, so if the app is refreshed the selection is gone. However I was hoping to remove the selection in the treeStore itself and refresh the view somehow so that users can immediately see the effect of their confirmation. I was following a tutorial for nestedList that I can't seem to find anymore, and this code is based on that:
var itemId = '';
Ext.define('MyApp.view.MainView',
{
extend: 'Ext.tab.Panel',
xtype: 'main',
alias: "widget.mainview",
requires: [
'Ext.dataview.NestedList',
'Ext.data.proxy.JsonP'
],
config:
{
tabBarPosition: 'bottom',
items: [
{
xtype: 'nestedlist',
title: 'Listings',
iconCls: 'home',
displayField: 'listingValue',
scrollable: true,
detailCard:
{
xtype: 'panel',
scrollable: true,
styleHtmlContent: true,
items: [
{
xtype: 'fieldset',
readOnly: true,
title: 'Schedule Information:',
items: [
{
name: 'from',
id: 'from',
xtype: 'textareafield',
label: 'From',
readOnly: true
},
{
name: 'to',
id: 'to',
xtype: 'textareafield',
label: 'To',
readOnly: true
},
{
name: 'moreInfo',
id: 'moreinfo',
xtype: 'textfield',
label: 'More Info',
readOnly: true
},
]
},
{
xtype: 'container',
flex: 1,
items: [
{
xtype: 'button',
text: 'Confirm',
action: 'confirmSelection',
margin: '10 5',
padding: '5',
ui: 'confirm'
}]
}]
},
listeners:
{
itemtap: function (nestedList, list, index,
element, post)
{
var detailCard = this.getDetailCard();
detailCard.setHtml('');
itemId = post.get('id');
Ext.getCmp('from').setValue(post.get(
'from'));
Ext.getCmp('to').setValue(post.get('to'));
Ext.getCmp('moreinfo').setValue(post.get(
'moreinfo'));
}
},
store:
{
type: 'tree',
fields: [
'id', 'from', 'to', 'fromcity', 'tocity',
'time', 'address',
{
name: 'leaf',
defaultValue: true
},
{
name: 'listingValue',
convert: function (value, record)
{
listingValue = '$<b>' + record.get(
'address') + '</b> ' + record
.get('fromcity') + ' to ' +
record.get('tocity');
return listingValue;
}
}
],
root:
{
leaf: false
},
proxy:
{
type: 'jsonp',
url: 'http://myURL.com/page.php?action=go',
reader:
{
type: 'json',
rootProperty: 'root'
}
}
}
},
{
title: 'Dashboard',
iconCls: 'action',
items: [
{
docked: 'top',
xtype: 'titlebar',
title: 'Dashboard'
},
]
}]
}
});
I have no idea what to do at this point, because the store is set up in the view and I'm not sure how to access it in my controller. I learned about treeStore.removeAll() and treeStore.load(), but how can I call those functions in a controller when the store is set up without any type of reference name? Is there a way I can remove the user's selection and display the view, or perhaps reload the view altogether so it can retrieve the new list from the server?
Because my list is on the first page of my app, I managed to get away with window.location.reload(); and reloading the whole app. Its not the most elegant solution, but the changes are reflected.
I won't accept my own answer just yet in case someone comes along with a better solution.

Categories