I tried this earlier and abandoned it because it returned 11 items when I was expecting just the 5 divs. I couldnt quite understand at the time and thought it was maybe also selecting TextNodes or lineBreak as a node. That is why I thought I should check if the nodeType was equal to 1
Maybe you can understand what its doing as the first few items in the elements object are this based on
[0] = "\n "Code:this.select('> *');
[1] = "div#pane"
[2] = "\n "
....
The html is roughly this:
Code:<div id="wrapper"> <div id="ext" class="pane">content</div> <div>content</div> <div>content</div> <div>content</div> <div>content</div> </div>
yes, all of Ext's DOM traversal methods should ignore text nodes, maybe?
like childElements in Prototype and getChildren in MooTools...
I would disagree with that. What if you wanted the textNodes?
Ext.select/query strengths are in their generic use, to get anything via a valid CSS selector.
If you don't want textNodes, filter them out:
Code:var elmsOnly = someParent.query('> *').filter(function(node){ return node.nodeType != 3; });
"be dom-ready..."
Doug Hendricks
Maintaining ux: ManagedIFrame, MIF2 (FAQ, Wiki), ux.Media/Flash, AudioEvents, ux.Chart[Fusion,OFC,amChart], ext-basex.js/$JIT, Documentation Site.
Got Sencha licensing questions? Find out more here.
You won't see the DomQuery updated to exclude the text entries, but here is an idea.
If you want to use select and get back a CompositeElementLite and you normally loop through the results using each, then the most efficient option may to add a new function to the CompositeElementLite called eachEl. Such a function which would skip the text node types. In this case the count would still show 11 but when you loop through, it only hits the five you want.
Here is an example
Code:Ext.override( Ext.CompositeElementLite, { /** * Calls each .. but skips the Text Elements * see each for details */ eachEl : function(fn, scope){ var me = this, el = me.el; Ext.each(me.elements, function(e,i) { el.dom = e; if( e.nodeType && e.nodeType != 3){ return fn.call(scope || el, el, me, i); } }); return me; } }) Ext.onReady(function(){ var el = Ext.get('wrapper'); var children = el.select('/ *'); //This returns all 11 alert( children.getCount() ); var ctr = 0; // ... however you can use eachEl to loop through only the elements children.eachEl( function(item){ ctr ++ }); alert( 'we looped ' + ctr ); })
Joseph Francis,
CoreLan / Meeting Consultants
If you want to integrate with / use Element select-like funtionality directlyfrom the element - then here are some random thoughts / implementations.
An extension of the previous simpler idea / post.
A bit out there but ....
This allows you to use selectEl at the element level just like select .. making for easer updates / cross over.
Code:Ext.override( Ext.CompositeElementLite, { /** * Calls the passed function passing (el, this, index) for each element EXCEPT TEXT NODES in this composite. <b>The element * passed is the flyweight (shared) Ext.Element instance, so if you require a * a reference to the dom node, use el.dom.</b> * @param {Function} fn The function to call * @param {Object} scope (optional) The <i>this</i> object (defaults to the element) * @return {CompositeElement} this */ eachEl : function(fn, scope){ var me = this, el = me.el; Ext.each(me.elements, function(e,i) { el.dom = e; if( e.nodeType && e.nodeType != 3){ return fn.call(scope || el, el, me, i); } }); return me; }, /** * Removes all text nodes from elements (not great performance here I'd imagine, use eachEl to just skip uneeded ones) * @return {CompositeElement} this */ elOnly : function(){ var me = this; var newelems = []; me.eachEl(function(el){ newelems.push(el.dom); }); me.elements = newelems; return me; } }) Ext.override( Ext.Element, { selectEl : function(selector,unique){ var ret = this.select(selector); return ret.elOnly(); }, selectChildren : function(){ return this.selectEl('> *'); } }) Ext.onReady(function(){ var el = Ext.get('wrapper'); var children = el.selectChildren(); // only the five alert( children.getCount() ); var ctr = 0; // ... can use each .. no need for eachEl children.each( function(item){ ctr ++ }); alert( 'we looped ' + ctr ); })
Joseph Francis,
CoreLan / Meeting Consultants
@Joe --
And what if I wanted all the empty textNodes (for replacement) whose previous sibling had an attribute bra="large" ?
Got an override for that?
That sort of filtering belongs in your application logic, especially considering all the possible CSS selector variants one might use in developing stuff for Core (or any framework).
IMHO: Javascript has plenty of Array.prototypes to handle that sort of thing. Let's not bloat Core for narrow use-cases.
But, hey, go nuts!![]()
"be dom-ready..."
Doug Hendricks
Maintaining ux: ManagedIFrame, MIF2 (FAQ, Wiki), ux.Media/Flash, AudioEvents, ux.Chart[Fusion,OFC,amChart], ext-basex.js/$JIT, Documentation Site.
Got Sencha licensing questions? Find out more here.
@ Joe Thanks for your help
I will apply those techniques and go through them in Firebug
Certainly there are many ways to do this and one of them may prove more useful as I add the rest of the functionality
I will certainly take the learning as best I can. I may have some questions
In fact where does the el(bold) come from in here?
and why is it passed in twice here(bolded again)?Code:eachEl : function(fn, scope){ var me = this, el = me.el;
Code:if( e.nodeType && e.nodeType != 3){ return fn.call(scope || el, el, me, i);
@andy ... one is for scope and the other is the first param of the function call.
@hendricd - you are obviously one of the smartest people arount and I have nothing but respect for you .. you are correct in what you say.
I knew that post would get answers like this ..
In fact, I agree about most of this should be at the app level and hence my "tossing out ideas" .. not "here is how you should do it".That sort of filtering belongs in your application logic, especially considering all the possible CSS selector variants one might use in developing stuff for Core (or any framework).
At the same time ... pulling DOM nodes using a selector and then filtering out the text nodes so you get back the same set of nodes with all browsers / that you really need / is another story. I can see a valid use for having such a function at a base level / built in so I provided such a solution for anyone that desires such a solution.
Joseph Francis,
CoreLan / Meeting Consultants