NOTE: I also created an Ext4 compatible version of this!
Keeping track of components in a large web apps gets harder as both the components and web apps grow. One issue with large components is that any individual piece of the component may need to be aware of other child or sibling pieces. An example of this would be if you have a save button in your component and when it is clicked, a text field must have its value validated before the save action takes place. The save button needs to be able to easily access the text field. I will demonstrate a simple and easy way to keep track of all of your components and child components with a small extension I created called Ext.ux.componentReference.
Rahul Singla has a great breakdown of the abilities provided by Ext to save component references. Rahul also provides a solution that this extension is loosely based from.
As Rahul states, the id approach is the least attractive method for referencing a component. Id values are defined globally throughout any given web page. If you need two of the same component on the same web page, you will have two components which share the same id values. This will cause issues because one id value will reference multiple components of different component instances.
The itemId approach is better because you have a localized identity value that can be referenced easily if you are aware of the component hierarchy.
The ref approach is the most flexible because you are able to place a reference in the parent component of your choosing using the '../../' notation, but this and the itemId approach both suffer from the same drawback in that they require knowledge of the parent component or component hierarchy.
Now I would like to introduce my approach, which I call Ext.ux.componentReference. Create a javascript file named Ext.ux.componentReference.js and place this code into it:
Now with some comments:
Upon instantiation of any component, this function will now be called before the component's initComponent function. You can read about how this works in the Ext Documentation under function -> createSequence. If any component (or it's parent) has the property "refO" (which must point to an object), any component (or it's children) with the property "itemId" will have a reference saved in "refO".
Here is an example:
While the result is unimpressive, the effect is powerful.
In this example we are referencing the 'icon' property of button1 from button2 and vice versa. Because the variable "this.panelRef" is now in scope within the entire testPanel component, this task becomes trivial.
Keeping track of components in a large web apps gets harder as both the components and web apps grow. One issue with large components is that any individual piece of the component may need to be aware of other child or sibling pieces. An example of this would be if you have a save button in your component and when it is clicked, a text field must have its value validated before the save action takes place. The save button needs to be able to easily access the text field. I will demonstrate a simple and easy way to keep track of all of your components and child components with a small extension I created called Ext.ux.componentReference.
Rahul Singla has a great breakdown of the abilities provided by Ext to save component references. Rahul also provides a solution that this extension is loosely based from.
id is almost always the least preferable option. You need to make sure manually that all items on the page whose ids are explicitly set by you are unique, which becomes quite difficult to ensure as the size and number of developers on the project increase.
itemId allows you to specify an id which is scoped locally for the container of the Component. However, if you have many deeply nested containers and components, getting your hands to a component considerably down in the hierarchy from a container listener function pretty up again becomes troublesome.
ref allows you to place a named reference to the Component along Container axis, and again requires you to navigate between container/component axis, which becomes complex as nesting increases. Moreover, the approach is unmaintainable if you later need to introduce an extra Container, which would force you to update all named ref instances placed below the new container added, as well as update javascript all over which used these named references.
As Rahul states, the id approach is the least attractive method for referencing a component. Id values are defined globally throughout any given web page. If you need two of the same component on the same web page, you will have two components which share the same id values. This will cause issues because one id value will reference multiple components of different component instances.
The itemId approach is better because you have a localized identity value that can be referenced easily if you are aware of the component hierarchy.
The ref approach is the most flexible because you are able to place a reference in the parent component of your choosing using the '../../' notation, but this and the itemId approach both suffer from the same drawback in that they require knowledge of the parent component or component hierarchy.
Now I would like to introduce my approach, which I call Ext.ux.componentReference. Create a javascript file named Ext.ux.componentReference.js and place this code into it:
Ext.Component.prototype.initComponent = Ext.Component.prototype.initComponent.createSequence(function(){ if(this.refO && this.itemId ){ this.refO[this.itemId] = this; }else if(this.ownerCt && this.ownerCt.refO ){ if(this.itemId ){ this.ownerCt.refO[this.itemId] = this; } if( !this.refO ){ this.refO = this.ownerCt.refO; } } }); |
Now with some comments:
Ext.Component.prototype.initComponent = Ext.Component.prototype.initComponent.createSequence(function(){ if(this.refO && this.itemId ){ //does the reference object and itemId exist? this.refO[this.itemId] = this; //save reference to component }else if(this.ownerCt && this.ownerCt.refO ){ //does owner have a reference object set? if(this.itemId ){ //is the itemId set? this.ownerCt.refO[this.itemId] = this; //save reference to component } if( !this.refO ){ //if the reference object is not set here, copy the parents down the component hierarchy this.refO = this.ownerCt.refO; //save reference to owner container's reference object so you can easily nest references very deep } } }); |
Upon instantiation of any component, this function will now be called before the component's initComponent function. You can read about how this works in the Ext Documentation under function -> createSequence. If any component (or it's parent) has the property "refO" (which must point to an object), any component (or it's children) with the property "itemId" will have a reference saved in "refO".
Here is an example:
<html> <body> <link rel="stylesheet" type="text/css" href="/inc/js/ext-3.2.1/resources/css/ext-all.css"> <script type="text/javascript" src="/inc/js/ext-3.2.1/adapter/ext/ext-base-debug.js"></script> <script type="text/javascript" src="/inc/js/ext-3.2.1/ext-all-debug.js"></script> <script type="text/javascript" src="/inc/js/Ext.ux.referenceObject.js"></script> <script type="text/javascript"> Ext.BLANK_IMAGE_URL = '/inc/img/s.gif'; testPanel = Ext.extend(Ext.Panel, { panelRef: {} ,initComponent:function(){ Ext.apply(this,{ title:'Test Panel' ,refO:this.panelRef ,frame:true ,width:200 ,height:200 ,layout:'absolute' ,items:[{ xtype:'button' ,text:'Button 1' ,itemId:'button1' ,x:20 ,y:10 ,icon:'/inc/img/disk.png' ,scope:this ,handler:function(){ Ext.Msg.alert('Button 1 Clicked!','The path to the icon of this button 2 is: '+this.panelRef['button2'].icon); } },{ xtype:'button' ,text:'Button 2' ,itemId:'button2' ,x:20 ,y:50 ,icon:'/inc/img/tick.png' ,scope:this ,handler:function(){ Ext.Msg.alert('Button 2 Clicked!','The path to the icon of this button 1 is: '+this.panelRef['button1'].icon); } }, new Ext.Button({ text:'Button 3' ,refO:this.panelRef ,itemId:'button3' ,x:20 ,y:90 ,icon:'/inc/img/cross.png' ,scope:this ,handler:function(){ Ext.Msg.alert('Button 3 Clicked!','The path to the icon of this button 2 is: '+this.panelRef['button2'].icon); } }) ] }); testPanel.superclass.initComponent.call(this); } }); Ext.onReady(function(){ testPanelInstance = new testPanel({ renderTo:document.body }); }); </script> </body> </html> |
While the result is unimpressive, the effect is powerful.
In this example we are referencing the 'icon' property of button1 from button2 and vice versa. Because the variable "this.panelRef" is now in scope within the entire testPanel component, this task becomes trivial.