Sencha Touch: searching components with classes with ComponentQuery() and down() - extjs

I have a problem and don't know if this is a bug or I misunderstood something. I wanted to search for a component with a specific class. Example:
Ext.define('Test', {
xtype: 'Test',
cls: ['cat', 'dog']
});
I wanted to find this component I created in a Ext.Container with this.down('Test[cls~=cat]') (I used ~= because the component has multiple classes). But I got undefined or null (don't know anymore) as a result.
With Ext.ComponentQuery.query('Test[cls~=cat]') I actually could find it.
Why is that? I thought down() is the same as Ext.ComponentQuery.query with the difference that it's search scope is not global.
I am using the current version of Sencha Touch.

No, this doesn't work. But you can use
this.query('Test[cls~=cat]')
or you use something like this:
Ext.ComponentQuery.pseudos.hasCls = function(items, cls) {
var i = 0, l = items.length, c, result = [];
for (; i < l; i++) {
var c = items[i];
if (c._cls && c._cls.indexOf(cls) > -1) {
return c;
}
}
return undefined;
};
and call it like:
this.down(".component:hasCls(cat)")

Related

Lazy repeat calculateItemHeight index is always undefined

I'm using ons-lazy-repeat and I want to have variable item heights depending on the item.
For that I'm using, as described in the documentation, a delegate object with a calculateItemHeight function.
The problem is all item heights are being set to 20 because initially the index variable is always undefined. Afterwards everything seems to work correctly but everything is already rendered on the ui.
Anyone else have the same problem? I don't see what I'm doing wrong here.
This is my delegate object:
$scope.TransactionDelegate = {
configureItemScope: function(index, itemScope) {
itemScope.item = TransactionService.allTransactions[index];
},
calculateItemHeight: function(index) {
if (!index)
return 20;
return 60;
},
countItems: function() {
return TransactionService.allTransactions.length;
},
destroyItemScope: function(index, scope) {
;
}
};
Thanks
This is a know bug that is now fixed and will be released in the next version.

How to use Ext.ComponentQuery.query with nested attributes

How to use Ext.ComponentQuery.query with nested attributes in Sencha Touch?
e.g
var myHardtoGetObj = topLevelView.down('someview[config.categoryCfg.id=1]')[0];
This gets me "uncaught error"
given :
Ext.define('SomeView', {
xtype : 'someview',
config : {
categoryCfg : {
id : 5,
name : 'someName'
}
}
});
Is this possible?
Thanks.
The canonical way of doing things like that is adding a custom pseudo class matcher:
Ext.ComponentQuery.pseudos.hasCategoryId = function(components, selector) {
var result = [],
c, i, len;
for (i = 0, len = components.length; i < len; i++) {
c = components[i];
if (c.config.categoryCfg && c.config.categoryCfg.id == selector) {
result.push(c);
}
}
return result;
}
Then you can use this pseudo class both globally with Ext.ComponentQuery.query, and locally with methods like query, down, etc.:
var allMatched, someComponent;
allMatched = Ext.ComponentQuery.query(':hasCategoryId(1)');
someComponent = myPanel.down(':hasCategoryId(42)');
See more ways to skin the cat in ComponentQuery doc.
This really is an interesting question. There doesn't seem to be an absolutely straightforward solution, however there is a rather quick workaround. You can modify your view code to:
Ext.define('SomeView', {
xtype : 'someview',
config : {
categoryCfg : {
id : 5,
name : 'someName'
}
},
hasCategoryId: function (id) {
return this.getCategoryCfg().id == id;
}
});
Then you can make a query like this:
Ext.ComponentQuery.query('someview{hasCategoryId(1)}');
or
topLevelView.down('someview{hasCategoryId(1)}');
Note: The syntax of the selector is xtype{memberMethod()} without a space in between. This way both selectors must match (the same way as .class1.class2 in CSS). Also the selectors must be in this order, because the result set is filtered by each selector in order and if some of the components don't have the hasCategoryId method it will break with just '{hasCategoryId(1)}'
Although not exactly answering the question but you can do a little work around to get it to work.
you can add update method to your nestedConfig like so
Ext.define('myCoolClass', {
config : {
nestedConfig : {
nestedId : 5
},
nestedId : null
},
updateNestedConfig: function (nestedConfig) {
if (nestedConfig.nestedId) {
this.setNestedId(nestedConfig.nestedId);
}
}
});
By doing that you now have access to normal component query attribute
Ext.ComponentQuery.query('[nestedId=555]')
As an example. If you take a look at Sencha source code they use this quite a lot like in NavigationView and TabPanels

How to know class A is extend from class B in ExtJs

I have a class A is extend from class B in ExtJs 4.x. Is there have a function judge class A is extend from class B like "if(obj instanceof Class)" in Java.
JS has an instanceof operator:
Ext.define('A', {
});
Ext.define('B', {
extend: 'A'
});
Ext.define('C', {
extend: 'B'
});
Ext.define('D', {
});
console.log(new B() instanceof A);
console.log(new C() instanceof A);
console.log(new D() instanceof A);
I recommend evans answer!
But there are other ways to do it on component level by using the getXTypes() method which returns the xType chain as string.
You need to lookup if the searched widget (component) is part of the string.
var splitted = ref.getXTypes().split('/'),
len = splitted.length,
i = 0;
for(;i < len; i++) {
if(lookupType == splitted[i])
// do something
}
Edit
Due to another problem I stumbled over another way that seems to work.
You can use the self, superclass and $className properties to navigate upwards in the class hierarchy.
Here's a example:
Ext.getCmp('customform-1746').self.superclass.$className // echo Ext.form.Panel
Ext.getCmp('customform-1746').self.superclass.self.superclass.$className // echo Ext.panel.Panel
You can simply build recursive method which checks and return either true or false. But again, the instanceof operator might be much faster here!
To expand on #sra's suggestion, you can also use isXType() on a component level: http://docs.sencha.com/extjs/4.2.2/#!/api/Ext.AbstractComponent-method-isXType

Check if a store (or records) have been edited?

I have a Grid Panel, which when I leave the page, I want a check to see if any items in the store (or iterate through models/records) to check if there are any unsaved changes/additions.
I initially tried using panel.getStore().getNewRecords() for new records, but it returns every record currently paged in. panel.getStore().getUpdatedRecords() seems to ignore records, despite lines in the grid having the small red triangle in each cell.
So can anyone advise on the correct way to check if any new or updated records exist in a store?
This may work for you.
var records = store.getRange();
for (var i = 0; i < records.length; i++) {
var rec = records[i];
if (rec.dirty == true) {
//Save data
}
}
In order to keep the dirty checking logic encapsulated, I chose to add an isDirty() method to the Ext.data.Store object. I utilized the same logic that AbstractStore.sync() uses to determine whether the store needs to sync.
Ext.define(null, {
override: "Ext.data.Store",
isDirty: function() {
return (this.getNewRecords().length > 0 || this.getUpdatedRecords().length > 0 || this.getRemovedRecords().length > 0);
}
});
I'm using ExtJS 4.2.1. If all of your records are returned when you call getNewRecords() you should check that you've set a value for idProperty on your model.
You can use something like the code below:
if(panel.getStore().getModifiedRecords().length > 0) {
console.log('store has dirty records');
}
I use this:
isStoreModified: function(store)
{
var modifiedRecords = store.getModifiedRecords();
return modifiedRecords && modifiedRecords.length && modifiedRecords.length > 0;
},
if (panel.getStore().needsSync) {
//store have unsaved changes.
}
If you are new to overriding here is #jstrickers answer for a mvc style program:
Create:
Ext.define('YourFolder.overridefolder.DataStore', {
override: "Ext.data.Store",
isDirty: function() {
return (this.getNewRecords().length > 0 || this.getUpdatedRecords().length > 0 || this.getRemovedRecords().length > 0);
}
});
Add this file to the appropriate folder and point to it in app.js 'required', then the isDirty will be available in your ext.data.store
Works great and the function will be available were you need it.
I based this off the answer by #theboulderer. I know this is an old thread, but I thought it might be useful for others who find this page.
I'm using the MVC model, so keep that in mind.
All you have to do is pass the store to the function, and it returns a boolean.
Usage:
if (this.isDirtyStore(myStore)){
...
}
Function:
isDirtyStore: function(theStore){
var isDirty = false;
theStore.each(function(item){
if(item.dirty == true){
isDirty = true;
}
});
if (!isDirty){
isDirty = (theStore.removed.length > 0);
}
return isDirty;
}
The answer by shw in this thread How do I get the dirty records from an ExtJS data store?, answers your question.
The trick is that the store reader needs to designate a idProperty or all rows are considered new.
They provide an example as well.

How to uncheck all tree nodes in Ext.tree.TreePanel?

I would like a 'reset' method to uncheck all the checked nodes in Ext.tree.TreePanel.
tree.getRootNode().cascade(function(n) {
var ui = n.getUI();
ui.toggleCheck(false);
});
As found here:
http://www.sencha.com/forum/showthread.php?12888-solved-programatically-unchecking-checked-tree-nodes&p=62845#post62845
I found a method as below, but seems the 'casecade' method do not worked well, I need call 'reset' several times to unchecked all the checked children:
reset: function (){
startNode = this.root;
var f = function () {
if (this.attributes.checked) {
this.attributes.checked = false;
this.getUI().toggleCheck(false);
}
};
startNode.cascade(f);
}
I was unable to get either of the other answers to work with Extjs 4.0.7. Also, the use of the "cascade" method issued a warning that it's deprecated. It recommended using "cascadeBy" instead. Other than the method name, I was unable to find a difference in the method signature (same arguments, this, behaviour).
However, I was able to find this code that worked:
{
xtype: 'button',
text: 'Deselect All',
listeners:{
click: function(){
var tree = Ext.ComponentQuery.query( 'treepanel[itemId=user_flags_tree]')[0];
tree.getRootNode().cascadeBy(function(){
this.set( 'checked', false );
});
}
}
}
Thanks to this post:
http://www.sencha.com/forum/showthread.php?149627-Programmaticaly-check-uncheck-checkboxes-in-the-Tree-panel
var nodes = treePanel.getView().getNodes();
var records = treePanel.getView().getRecords(nodes);
for (var i = 0; i < records.length; i++) {
records[i].set('checked',true);
}

Resources