
Latest posts by Nenad (see all)
- Traquer – Testing made easy - October 25, 2016
- ExtJS tag cloud - June 28, 2016
- Interactive Twitter stream visualization now online! - June 16, 2016
DOM lookup can be hell of a job, because it’s structure can be monstrouos in case of serious web sites, not to mention heavy one-page web apps. That’s why we, today, have some cool libraries (like jQuery) that perform some heavy DOM-search using naïve syntax, like $(‘span.some-class-i-like’).
Even though in modern JavaScript we can pretty much rely on query selectors (document.querySelector, document.querySelectorAll) it can be real pain to distinguish whether one of those nodes that you’ve found using the aforementioned is the one you really want. One of further pains is that you’ll have to iterate through each one of newly discovered nodes and compare it against some condition. And that is only in case you’re searching complete DOM tree, which you won’t do every time you need a close sibling, because it’s slow, expensive and wastes your, and end-user’s time.
In most of the cases (except you’re about to write your own library) your business would be to create something like big serious business web application, and you won’t have time to play around with vanilla JS and plain DOM.
(*Except you’re a DOM and JS savvy, and you can deliver fast which is rare).
That’s the moment where you’ll have to make a choice: Am I going to make my life a misery or not?
Of course, that question is sublimation of complete business you’re about to do. If you plan to fail, you can go with plain JS, you’ll certainly learn a lot, but you will be late to deliver.
If you choose to act smart, you can rely on ExtJs’s methods of component hierarchy, finding them, going up and down, querying, selecting, flying etc. Since this framework is pretty mature right now, you won’t have to deal with issues like browser compatibility.
I’ll try to cover some of basic ways of component lookups, and give you some hints, since there are so many ways in ExtJs, that this article could easily evolve into a book.
Search by whatever
The most basic way (as Goran mentioned it is previous post is getting component by it’s id (if you gave one to a component):
1 2 3 4 5 6 7 8 9 |
{ region: 'center', id: 'centerTabPanel', xtype: 'tabpanel', items:[{ title: 'Tab 1', html: '<h2>Content appropriate for the current navigation.</h2>' }] } |
Finding it:
Ext.ComponentManager.get(‘centerTabPanel’);
And this will search through the list of registered components in ExtJs’s Component Manager, matching the one you requested. Of course, giving an id to component it cool thing to do for the parts that are always going to be there, since ids are unique, and giving the same id to multiple components would result in a mess.
When it comes to components that you don’t want to label like this, you can use itemId.
1 2 3 4 5 6 7 8 9 |
{ region: 'center', itemId: 'centerTabPanel', xtype: 'tabpanel', items:[{ title: 'Tab 1', html: '<h2>Content appropriate for the current navigation.</h2>' }] } |
In this case, Ext.ComponentManager.get or Ext.getCmp methods are futile. They will return undefined.
In cases like this, Ext.ComponentQuery.query comes to the rescue. This is mighty tool that provides functionality of document.querySelectorAll but will return complete (JavaScript) Ext Js object, not only it’s DOM emanation. So the call will be:
Ext.ComponentQuery.query(‘#centerTabPanel’);
And it will return an array (of components it found), of which the first (and only in this case) element will be our centerTabPanel. In case you named several other tabpanels with this itemId, it would return an array of all those components.
And the fun has only just started. Ext.ComponentQuery.query as it’s name says, can query the DOM (and Component Manager) against lots of features, like xtype, title, region, your_own_property etc.
So if you have component that looks like this:
1 2 3 4 5 6 7 8 9 |
{ region: 'center', mySuperProp: 'superProp', xtype: 'tabpanel', items:[{ title: 'Tab 1', html: '<h2>Content appropriate for the current navigation.</h2>' }] } |
you can write your query like this:
Ext.ComponentQuery.query(‘[mySuperProp=”superProp”]’);
and you will get your component by completely custom property. Not to mention, casting by xtype (which can be super-handy):
Ext.ComponentQuery.query(‘[xtype=”tabpanel”]’);
or region:
Ext.ComponentQuery.query(‘[region=”center”]’);
Note that all of those methods returned the same result: an array with one same first object – our beloved tabpanel.
Ups and downs
As I mentioned before, you won’t be searching complete Component Manager or DOM all the time, since it can be slow, especially if you’re doing it too often during application’s start up time or component initialization, creation etc. In some cases your searched are going to be more focused. Let’s examine this scenario:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
{ region: 'center', mySuperProp: 'superProp', xtype: 'tabpanel', items:[{ title: 'Tab 1', html: '<h2>Content appropriate for the current navigation.</h2>', listeners: { afterrender: function(){ console.log(this.up()); } } }] } |
You have decided to get previous component from first of your tabs on after the component is rendered, inside tabpanel component. The console will log our center tabpanel, since we’ve gone just one level up in our tree. That’s just ok, what about this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
{ region: 'center', mySuperProp: 'superProp', xtype: 'tabpanel', items:[{ title: 'Tab 1', html: '<h2>Content appropriate for the current navigation.</h2>', listeners: { afterrender: function(){ console.log(this.up('[mySuperProp="superProp"]')); } } }] } |
Yes! You can do that, you can query your upper components using queries. Let’s see another scenario:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
Ext.define('usertrack.view.main.Main', { extend: 'Ext.container.Container', requires: [ 'usertrack.view.main.MainController', 'usertrack.view.main.MainModel' ], xtype: 'app-main', controller: 'main', viewModel: { type: 'main' }, layout: { type: 'border' }, items: [{ xtype: 'panel', bind: { title: '{name}' }, region: 'west', html: '<ul><li>This area is commonly used for navigation, for example, using a "tree" component.</li></ul>', width: 250, split: true, tbar: [{ text: 'Button', handler: 'onClickButton' }] },{ region: 'center', id: 'centerTabPanel', mySuperProp: 'superProp', xtype: 'tabpanel', items:[{ title: 'Tab 1', html: '<h2>Content appropriate for the current navigation.</h2>', listeners: { afterrender: function(){ console.log(this.up('[xtype="app-main"]')); } } }] }] }); |
Yup. You can query even more up, or simply call:
this.up(‘app-main’);
The result will be the same – you’ll get the mail view in this case.
Going down is similar so I won’t show snippets for that case. The only thing you’ll have keep in mind is an application’s lifecycle, and the time of component’s availability – the time when they’re created. In these examples I used afterrender event since I was sure that components I’m searching for are ready rendered.
This won’t be the case all the time, sometimes your component tree can be pretty large and rendering time can took some time, so you will have to check whether the component is .rendered:
1 2 3 |
if(component.rendered){ ... } |
and if not, you can give it a provisional time to render (not a very smart idea):
1 2 3 4 5 |
if(!component.rendered){ Ext.defer(function(){ ... }, 20, this); // some provisional time I think the component will be rendered in } |
I don’t recommend this, but it can be useful in times you want to cheat :).
Share the post "Finding components, DOM elements or whatever using ExtJs"