PDA

View Full Version : [FIXED] Ext.ComponentQuery - query by alternate alias fails



LesJ
27 May 2011, 12:02 PM
Go here:

http://dev.sencha.com/deploy/ext-4.0.1/examples/grid/array-grid.html

This query works:

Ext.ComponentQuery.query("gridpanel")

This query fails:

Ext.ComponentQuery.query("grid")

Both queries should return the same result since Ext.grid.Panel has two aliases.


Ext.define('Ext.grid.Panel', {
extend: 'Ext.panel.Table',
requires: ['Ext.grid.View'],
alias: ['widget.gridpanel', 'widget.grid'],
....

Artur Bodera (Joust)
31 May 2011, 3:30 AM
True. That's puzzling....

Here's a fiddle with the bug:
http://jsfiddle.net/Thinkscape/rNtHe/

rex.staples
7 Jun 2011, 2:07 PM
I found the same thing when wiring up the events for a combobox. The selector only works against the first item declared in a class definition ('combobox' works, 'combo' does not work)


alias: ['widget.component', 'widget.box']
alias: ['widget.checkboxfield', 'widget.checkbox']
alias: ['widget.combobox', 'widget.combo']
alias: ['widget.filefield', 'widget.fileuploadfield']
alias: ['widget.hiddenfield', 'widget.hidden']
alias: ['widget.radiofield', 'widget.radio']
alias: ['widget.textareafield', 'widget.textarea']
alias: ['widget.triggerfield', 'widget.trigger']
alias: ['widget.gridpanel', 'widget.grid']
alias: ['widget.image', 'widget.imagecomponent']
alias: ['widget.slider', 'widget.sliderfield']


Here's why only the first alias gets applied (note the very last code comment):


Manager.registerPostprocessor('alias', function(name, cls, data) {
var aliases = data.alias,
widgetPrefix = 'widget.',
i, ln, alias;

if (!(aliases instanceof Array)) {
aliases = [aliases];
}

for (i = 0, ln = aliases.length; i < ln; i++) {
alias = aliases[i];


this.setAlias(cls, alias);
}

// This is ugly, will change to make use of parseNamespace for alias later on
for (i = 0, ln = aliases.length; i < ln; i++) {
alias = aliases[i];

if (alias.substring(0, widgetPrefix.length) === widgetPrefix) {
// Only the first alias with 'widget.' prefix will be used for xtype
cls.xtype = cls.$xtype = alias.substring(widgetPrefix.length);
break;
}
}
});


The above is from ext-debug.js

rex.staples
10 Jun 2011, 2:20 AM
Here is a complete testbed which fixes the problem by overriding Ext.AbstractComponent.getXTypes(). This was the easiest way for me to deliver a fix in 1 piece.

My first attempt at this solution modified the implementation of the function passed to Manager.registerPostprocessor('alias', <impl function>) in ext-debug.js ... I ended up using a different method that gets progressively faster as more and more base classes get their xtypes chain calculated.

This solution below does not do anything to the registerPostprocessor <impl function> and instead focuses on adding alias support to the implementation of Ext.AbstractComponent.getXTypes() ... that said, the loop in ext-4.0.2/ext-debug.js ~ line 6644 could easily be modified and migrated into the (identical) loop above it.



<!DOCTYPE html>
<html>
<head>
<title>Test</title>
<script type="text/javascript" src="../ext-4.0.2/ext-debug.js"></script>
<script type="text/javascript">

Ext.define('Test.view.Viewport', {
extend: 'Ext.container.Viewport',
id: 'appwin',
alias: ['widget.vp1', 'widget.canvasviewport'],
requires: ['Ext.form.field.TextArea'],
items: { xtype: 'textareafield' }
});

Ext.define('Test.controller.Main', {
extend: 'Ext.app.Controller',
init: function() {
this.control({
'textarea': {
afterrender: function() { console.log('afterrender works!'); }
}
});
}
});

Ext.onReady(function() {

Ext.AbstractComponent.override({
/**
* This implementation of getXTypes recursively builds an ancestor
* xtypes chain saving the chain at each level for faster subsequent
* lookups (common base classes are only ever calculated 1 time).
*/
getXTypes: function() {
var self = this.self,
widgetPrefix = 'widget.',
parentPrototype = this.superclass,
xtypes, i, ln, alias, aliases, cls;

if (self.xtypes === undefined) {

// fetch the ancestor xtypes chain
if (parentPrototype && (cls = Ext.getClass(parentPrototype))) {
if (cls.xtypes !== undefined) {
xtypes = cls.xtypes;
// parent xtypes has already been calculated
} else {
/* DEV NOTE:
This implementation reduces recursive calls by skipping
over superclass ancestors that do not have an xtype */

// continue up the chain until an object with an xtype is found
// or until the end of the chain is reached
while (parentPrototype && cls && cls.xtype === undefined) {
if (parentPrototype = parentPrototype.superclass) {
cls = Ext.getClass(parentPrototype);
}
}

// if the end of the chain was not reached, then recursively
// calculate the parent xtypes
if (cls && cls.xtype !== undefined) {
xtypes = parentPrototype.getXTypes();
}
}

/* DEV NOTE:
This alternative implementation is simpler than the else
above at the cost of a few redundant recursive calls
*/
//} else if (parentPrototype.getXTypes) {
// xtypes = parentPrototype.getXTypes();
//}
}

// if the ancestor chain was populated seed it into the array for
// calculating this class's xtypes
xtypes = xtypes ? [xtypes] : [];

// add to any ancestor xtypes chain by processing our aliases
aliases = Ext.ClassManager.getAliasesByName(this.$className);

// code borrowed from Ext 4.0.2 ext-debug.js ~ lines 6643 with this note:
// ---> This is ugly, will change to make use of parseNamespace...
for (i=0, ln = aliases.length; i < ln; i++) {
alias = aliases[i];
if (alias.substring(0, widgetPrefix.length) === widgetPrefix) {
xtypes.push(alias.substring(widgetPrefix.length));
}
}

self.xtypes = xtypes.join('/');
//console.log(this.$className,
// '.getXTypes :: [', self.xtype, '] --> ', self.xtypes);
}

return self.xtypes;
}
});


});

Ext.application({
autoCreateViewport: true,
name: 'Test',
controllers: ['Main'],
launch: function() {

var t = new Ext.form.field.TextArea();
console.log('Ext.form.field.TextArea.getXTypes(): ', t.getXTypes());

var q = new Ext.tip.QuickTip();
console.log('Ext.tip.QuickTip.getXTypes(): ', q.getXTypes());
}
});


</script>
</head>
<body></body>
</html>


I learned a ton about the class manager and saw some really interesting short-circuit techniques that I am going to adopt. I must say I absolutely love the modularized source -- it makes this kind of debugging exercise fun.

Nickname
29 Jun 2011, 10:51 AM
REQUIRED INFORMATION Ext version tested:

Ext 4.0.2a
since preview

Browser versions tested against:

FF4.0.1 (firebug 1.7.3 installed) Ubunutu 10.10
12.0.742.91 (87961) Ubuntu 10.10

Description:

Ext.ComponentQuery.query return empty array if queried by alternate alias
affects component.up()/.down()/.child()

Steps to reproduce the problem:

Goto http://dev.sencha.com/deploy/ext-4.0.2a/examples/grid/live-search-grid.html
Use FireBug or Chrome Developer Tools
Run in the console:
1. Ext.ComponentQuery.query('grid')
2. Ext.ComponentQuery.query('gridpanel')
3. Ext.ComponentQuery.query('gridpanel')[0].down('checkbox')
4. Ext.ComponentQuery.query('gridpanel')[0].down('checkboxfield')
5. Ext.ComponentQuery.query('checkboxfield').down('grid')
6. Ext.ComponentQuery.query('checkboxfield').down('gridpanel')

The result that was expected:

1. array with 1 grid reference
2. array with 1 grid reference
3. reference to first checkbox field in the grid
4. reference to first checkbox field in the grid
5. reference to grid
6. reference to grid

The result that occurs instead:

1. empty array
2. array with 1 grid reference
3. undefined
4. reference to first checkbox field in the grid
5. undefined
6. reference to the grid instance

Test Case: see above?!

HELPFUL INFORMATION

See this URL for live test case: http://dev.sencha.com/deploy/ext-4.0.2a/examples/grid/live-search-grid.html

Debugging already done:


See Post #3


Is affected the Components: ext-4.0.2a/src# find . -exec grep "alias: *\[.*,.*\]" '{}' \; -print
alias: ['proxy.jsonp', 'proxy.scripttag'],
./data/proxy/JsonP.js
alias: ['widget.image', 'widget.imagecomponent'],
./Img.js
alias: ['layout.auto', 'layout.autocontainer'],
./layout/container/Auto.js
alias: ['widget.component', 'widget.box'],
./Component.js
alias: ['widget.combobox', 'widget.combo'],
./form/field/ComboBox.js
alias: ['widget.hiddenfield', 'widget.hidden'],
./form/field/Hidden.js
alias: ['widget.triggerfield', 'widget.trigger'],
./form/field/Trigger.js
alias: ['widget.filefield', 'widget.fileuploadfield'],
./form/field/File.js
alias: ['widget.textareafield', 'widget.textarea'],
./form/field/TextArea.js
alias: ['widget.checkboxfield', 'widget.checkbox'],
./form/field/Checkbox.js
alias: ['widget.radiofield', 'widget.radio'],
./form/field/Radio.js
alias: ['widget.slider', 'widget.sliderfield'],
./slider/Single.js
alias: ['widget.gridpanel', 'widget.grid'],
./grid/Panel.js

Possible fix:

See Post #4

Operating System:

Ubuntu 10.10




Could not find any opend bug report and so used the bug template

Nickname
31 Jul 2011, 7:32 AM
4 weeks without reponse

*push*

edspencer
3 Aug 2011, 6:03 AM
Hey @nickname, sorry for the delayed response. This is now fixed locally and will be present in the next release

Nickname
3 Aug 2011, 6:53 AM
Thank you very much for the update!