From all the examples I found, using is(':checked') should return true if checkbox is checked, and false if not. In my case it returns false on both situations. What is my mistake?
{
xtype: 'checkbox',
boxLabel: 'Show message',
id: 'mainBox',
handler: function() {
alert($(this).is(':checked'));
}
In accordance to the ExtJS documentation, I would try this:
{
xtype: 'checkbox',
boxLabel: 'Show message',
id: 'mainBox',
handler: function (field , value) {
alert(value);
}
}
Because this inside a extjs event handler does not refer to the dom element instead this will refer to a extjs checkbox object. jQuery won't be able to find out the target element using the extjs object reference. Instead you have the getValue() method of checkbox which will return the checked state value, so
Try
{
xtype: 'checkbox',
boxLabel: 'Show message',
id: 'mainBox',
handler: function (el) {
alert(el.getValue());
}
}
As you can read in the jQuery documentation, the .is('...') function returns an jQuery object.
If you want some kind of a boolean as return value, you can try the following code:
alert($(this).is(':checked').length > 0);
But for a checkbox element, using the 'checked' property should work too:
alert(this.checked);
You can even try this if you want to use jQuery:
alert($(this).attr('checked') === 'checked');
Related
A component definition:
Ext.define('Retroplanner.view.dimension.DimensionMapping', {
alias: 'widget.dimensionMapping',
extend: 'Ext.form.Panel',
...
items: [{
xtype: 'combo'
}, ...
]
A 'select' handler of the child item must create a widget and add this widget to the items array of its parent.
Inside of this child item, it its 'select' handler, I can find its parent by some search techniques. But I would like to avoid it if it is possible. I do not have a reference variable to the parent neither.
A better approach would be - to create function in the parent, and attach it somehow to the child item:
Ext.define('Retroplanner.view.dimension.DimensionMapping', {
...
onSiRemoteCombo: function(cmb, rec, idx) {
alert("select handler");
var newItem = Ext.widget('somexType');
this.items.add(newItem);
}
The question, how to attach onSiRemoteCombo?
I've found a similar solution here: How to create listener for child component's custom event
First, it does not work for me. I can give a full example that I tried to use.
2nd, I would like to create items via the most common way/in the common place, not via initComponent method. I would like to have something like:
Ext.define('Retroplanner.view.dimension.DimensionMapping', {
...
afterRender: function() {
var me = this;
//exception here
//Uncaught TypeError: Cannot read property 'on' of undefined
me.items[0].on('select', onSiRemoteCombo, this);
},
items: [{
xtype: 'combo'
}, ...
],
onSiRemoteCombo: function(cmb, rec, idx) {
alert("Ttt");
var dimensionMapping = Ext.widget('propGrid');
this.getParent().add(dimensionMapping);
}
But I get an exception:
//exception here
//Uncaught TypeError: Cannot read property 'on' of undefined
me.items[0].on('select', onSiRemoteCombo, this);
And also, attach a listener after each rendering, really is a bad idea.
Are there any best practices for such use cases? Ideally, if it will work in different versions of Ext JS, at least in 5.x and 6.x
Attach a handler in a child and access its parent? A child should not depend on its parent. Only parent should know, what to do.
One way to solve this is by wrapping the combo item component initialization into form's initComponent method. This way when setting a listener for the combo, you can use this.formMethod to reference a form method. Here is some code:
Ext.define('Fiddle.view.FirstForm', {
extend: 'Ext.form.Panel',
bodyPadding: 15,
initComponent: function () {
Ext.apply(this, {
items: [{
xtype: 'combo',
fieldLabel: 'First Combo',
store: ['first', 'second'],
listeners: {
'select': this.onComboSelect
}
}]
});
this.callParent();
},
onComboSelect: function () {
alert('I am a first form method');
}
});
The second approach by using a string listener on the combo, and by setting defaultListenerScope to true on the form. This way the listener function will be resolved to the form's method. Again, some code:
Ext.define('Fiddle.view.SecondForm', {
extend: 'Ext.form.Panel',
bodyPadding: 15,
defaultListenerScope: true,
items: [{
xtype: 'combo',
fieldLabel: 'Second Combo',
store: ['first', 'second'],
listeners: {
'select': 'onComboSelect'
}
}],
onComboSelect: function () {
alert('I am a second form method');
}
});
And here is a working fiddle with both approaches: https://fiddle.sencha.com/#view/editor&fiddle/27un
A panel contains of 3 items. The last item has an event handler attache. In the handler a new item (widget) is added to the parent panel. Before adding a new item, an old item of the same xtype should be deleted.
Here is an example that does not work:
Ext.define('Retroplanner.view.dimension.DimensionMapping', {
extend: 'Ext.form.Panel',
defaultListenerScope: true,
items: [{
xtype: 'component',
html: '<h3> Dimension Mappings</h3>',
},{
xtype: 'bm-separator'
},{
xtype: 'siRemoteCombo',
...
listeners: {
'select': 'onSiRemoteCombo'
}
}
],
onSiRemoteCombo: function(cmb, rec, idx) {
var item;
for(item in this.items){
//here item - is undefined,
//although this.items.length=3, as expected
//alert(item.xtype);
//isXType is not defined for undefined element:
if (item.isXType('propGrid')) {
this.remove(item);
break;
}
}
//the following code works as expected, if the previous is commented
var dimensionMapping = Ext.widget('propGrid');
this.items.add(dimensionMapping);
this.updateLayout();
}
});
I tried to use index, but it also does not work:
Ext.define('Retroplanner.view.dimension.DimensionMapping', {
...
defaultListenerScope: true,
items: [{
xtype: 'component',
...
},{
xtype: 'bm-separator'
},{
xtype: 'siRemoteCombo',
...
listeners: {
'select': 'onSiRemoteCombo'
}
}
],
onSiRemoteCombo: function(cmb, rec, idx) {
//the following code does not remove item in GUI interface.
if (this.items.length == 4)
this.remove(this.items[3], true);
var dimensionMapping = Ext.widget('propGrid');
this.items.add(dimensionMapping);
this.updateLayout();
}
});
I would like to be able to remove item by xtype, without any id or other types of references. But if it is not possible, which is the best way to do it? To remove GUI component from its container.
Check out component queries. It allows you to search for ExtJS components based on their attributes, globally or from within a container.
For easy access to queries based from a particular Container see the
Ext.container.Container#query, Ext.container.Container#down and
Ext.container.Container#child methods. Also see Ext.Component#up.
For your case down or child are appropriate. Something like this:
this.remove(this.down('propGrid'))
Here is a working fiddle: https://fiddle.sencha.com/#view/editor&fiddle/27vh. Just select a value from the combo, and the grid will be removed.
To remove an item with the prodGrid xtype, try this:
onSiRemoteCombo: function(cmb, rec, idx) {
if (this.down('prodGrid'))
this.remove(this.down('prodGrid'))
var dimensionMapping = Ext.widget('propGrid');
this.items.add(dimensionMapping);
this.updateLayout();
}
This is a follow up question that I got answered here: How can I programmatically set column filters?
I have a 188 line Ext.js view. In this view I extend Ext.grid.Panel and in this grid I have set the selModel like so ...
selModel: {
cellSelect: false, // Only support row selection.
type: 'spreadsheet' // Use the new "spreadsheet" style grid selection model.
},
On one of the columns, the Status column, I am programmatically setting the filter so that only rows that have the Status of Ready will appear when the page firsts renders. I have been doing this here in the code:
columns: [
...
{
text: 'Status',
dataIndex: 'status',
itemId: 'status',
renderer: function(value, metaData) {
var filter = this.up('panel').down('#status').filter;
if (!filter.menu) {
filter.createMenu();
filter.menu
.down('menuitem[value="Ready"]')
.setChecked(true);
}
metaData.tdStyle = (value == 'Ready') ?
'color:green;font-weight: bold' :
'color:red;font-style: italic'
return(value)
},
filter: 'list',
flex: 1,
},
... more columns ...
A helpful SO member pointed out that is not the most efficient place for the code that sets the filter as the code will be executed for each row in the grid.
I have tried adding an afterrender function like so ...
{
text: 'Status',
dataIndex: 'status',
itemId: 'status',
renderer: function(value, metaData) {
metaData.tdStyle = (value == 'Ready') ?
'color:green;font-weight: bold' :
'color:red;font-style: italic'
return(value)
},
filter: 'list',
flex: 1,
listeners: {
afterrender: function(value) {
Ext.Msg.alert('We have been rendered value is ' + value );
var filter = this.up('panel').down('#status').filter;
if (!filter.menu) {
filter.createMenu();
filter.menu
.down('menuitem[value="Ready"]')
.setChecked(true); //Uncaught TypeError: Cannot read property 'setChecked' of null
}
}},
... but that results in this error message, //Uncaught TypeError: Cannot read property 'setChecked' of null.
What am I doing wrong here? Do I need the listeners:? Am I not getting passed the data I think I am getting passed to my afterrender function? Should I defining a initComponent function?
UPDATE:
I changed my code to what DrakeES suggested, ...
{
text: 'Status',
dataIndex: 'status',
itemId: 'status',
renderer: function(value, metaData) {
metaData.tdStyle = (value == 'Ready') ?
'color:green;font-weight: bold' :
'color:red;font-style: italic'
return(value)
},
flex: 1,
filter: {
type: 'list',
value: 'Ready'
}
... but the result is this:
Where the animated loading image just sits there and spins. This prevents the user from be able to change the filter interactively. I wonder what it is I am doing wrong here?
I am programmatically setting the filter so that only rows that have
the Status of Ready will appear when the page firsts renders
What checking the filter's checkbox effectively does is setting filter on the store. Because you want the filter to be applied initially, it would be better to have it in the store config right away:
filters: [
{
id: 'x-gridfilter-status',
property: 'status',
value: 'Ready'
}
]
That way the grid view appear filtered in the first place — instead of initially showing all rows and only then filtering them out once the column menu renders and applies the filter. Note that having id: 'x-gridfilter-status' on the store's filter is required so that the column's filter picks it up instead of creating a duplicate.
Setting filter on the store, however, will not send feedback to the column filter menu, so the latter will remain unchecked unless you explicitly check it. Therefore, you still need an afterrender handler on either the grid or the column to make things look in sync.
A simple and elegant solution without listeners and stuff:
filter: {
type: 'list',
value: 'Ready'
}
Full working example: https://fiddle.sencha.com/#fiddle/prp
I am trying to get value of this checkbox
Ext.define('myRoot.myExtApp.myForm', {
extend: 'Ext.form.Panel',
layout: {
type: 'vbox',
align: 'stretch'
},
scope: this,
constructor: function() {
this.callParent(arguments);
this.myFieldSet = Ext.create('Ext.form.FieldSet', {
scope: this,
columnWidth: 0.5,
collapsible: false,
defaultType: 'textfield',
layout: {
type: 'hbox', align: 'stretch'
}
});
this.mySecondForm = Ext.create('myRoot.myExtApp.myForm2', {
scope: this,
listener: this,
margin: '1 3 0 0'
});
this.myCheckBox = Ext.create('Ext.form.Checkbox', {
scope: this,
//id: 'myCheckBox',
boxLabel: 'Active',
name: 'Active',
checked: true,
horizontal: true
});
this.myFieldSet.add(this.mySecondForm);
this.myFieldSet.add(this.myCheckBox);
this.add(this.myFieldSet);
}
});
As you can see I have another form
Ext.define('myRoot.myExtApp.myForm2', {
where I have a handler, that should get the value of the checkbox from "myForm"
How can I get the value of my checkbox from Form2 without using Ext.getCmp? I know I can get the value of the checkbox if I do
Ext.getCmp('myCheckBox').getValue();
but using
this.myCheckBox.getValue();
gives me undefined error.
UPDATE - with Wared suggestion I tried this inside myForm2
this.temp=Ext.create('myRoot.myExtApp.myForm'), {});
var tempV = this.temp.myCheckBox.getValue();
I was able to get the value but I get the same true value even if I uncheck the box
I assume you worry about performance loss due to excessive use of component queries. A nice trick to minimize component queries could be to define a new method inside a closure in order to cache the result of the first getCmp call. Wrapping the definition of the method inside a closure allows to avoid using global scope or a useless class property.
getMyCmp: function (cmp) {
// "cmp" does not exist outside this function
return function () {
return cmp = cmp || Ext.getCmp('#myCmp');
};
}()
One solution could be :
myRoot.myExtApp.myForm.myCheckBox.getValue();
Beware, wrong answer. See comments below for a valid solution.
I have an issue with the next code block:
run: function(e, row){
var me = this;
var container = Ext.getCmp('centercontainer');
try {
container.removeAll();
} catch(e) { }
// This block is called from another file, I just put it here to show you.
me.panels = [{
xtype: 'tabpanel',
id: 'containertabpanel',
items: [{
itemId: 'package',
title: me.PackageTitle
},{
itemId: 'excursion',
title: me.ExcursionTitle
}]
}];
// Reset
container.setTitle(me.EditDestinationTitle + row.data.name);
container.add(me.panels);
me.tabs = container.getComponent('containertabpanel');
// console.log(Ext.ComponentQuery.query('#containertabpanel > #package'))
me.control({
// Work with
// 'tab': {
// Doesn't work
'containertabpanel > package': {
mouseover: me.doPackage
}
})
},
Anyone knows how do I get to catch the click event of "package" item of tabpanel component?
I saw when I use just "tab" selector on this.control query, that work, but I can't get only "package" tab component.
Thank you in advance.
In your definition of your tabpanel you can specify -
listeners:{
click:{
fn: function(){
//click handling code goes here
}
}
}
If I understood correctly this is controller code and you are trying to catch an item click on the panel which is one of many in a tabpanel
What you can do is identify your panel by any property that is unique to it via the component query syntax like this: button[myprop=blah]
This syntax will match any buttons on the page with the following config:
{
xtype:'button'
myprop:'blah'
}
In your case you can try tab[itemId=package]
What you also need to be careful about is controller can listening only for events that are fired by the components. Make sure the event you are listening for is fired (check the docs). You can always fire custom events if necessary.
You need to do this
me.control({
// Work with
// 'tab': {
// Doesn't work
'containertabpanel > #package': {
mouseover: me.doPackage
}
})