AJAX In Action [294]
In fact, it won’t, because the myObj.clickHandler function will get borrowed by the browser (just as our wayward dog borrowed a method from the tree object in the previous section) and invoked in the context of the element, not the Model object. Since the element happens to have a built-in id property, it will show a value, and, depending on your naming conventions, it may even be the same as the Model object’s ID, allowing the misunderstanding to continue for some time. If we want the event handler to refer to the Model object that we’ve attached it to, we need another way of passing the reference to that object across. There Licensed to jonathan zheng Methods and functions 611 are two idioms for doing this that I’ve commonly come across. One is clearly superior to the other, in my opinion, but I coded for years using the other one, and it works. One of the aims of this book is to give names to the patterns (and anti-patterns) that we have adopted by habit, so I will present both here. Referencing the Model by name In this solution, we assign a globally unique ID to each instance of our Model object and keep a global array of these objects referenced by the ID. Given a reference to a DOM element, we can then reference its Model object by using part of the ID as a key to the lookup array. Figure B.1 illustrates this strategy. Generating a unique ID for every element is an overhead in this approach, but ID generation can be accomplished fairly automatically. We can use the array length as part of the key, for example, or a database key, if we’re generating code on the web server. As a simple example, we’re creating an object of type myObj, which has a clickable title bar that invokes a function myObj.foo(). Here is the global array: var MyObjects=new Array(); And here is the constructor function, which registers the Model object with that array: Model object DOM element 3. Retrieve reference to Model 2. Query lookup with id fragment 1. Resolve this.id and Global lookup extract fragment Event handler Figure B.1 Referencing the Model from an event handler function by name. The DOM element ID is parsed, and the parsed value used as a key to a global lookup array. Licensed to jonathan zheng 612 APPENDIX B JavaScript for object-oriented programmers function myObj(id){ this.uid=id; MyObjects[this.uid]=this; ... this.render(); } Here is a method of the myObj object, which does something exciting. We want to invoke this when the title bar is clicked: myObj.prototype.foo=function(){ alert('foooo!!! '+this.uid); } Here is the object’s render() method, which creates various DOM nodes: myObj.prototype.render=function(){ ... this.body=document.createElement("div"); this.body.id=this.uid+"_body"; ... this.titleBar=document.createElement("div"); this.titleBar.id=this.uid+"_titleBar"; this.titleBar.onclick=fooEventHandler; ... } When we construct any DOM nodes in the view for this Model object, we assign an ID value to them that contains the Model object ID. Note that we refer to a function fooEventHandler() and set it as the onclick property of our title bar DOM element: function fooEventHandler(event){ var modelObj=getMyObj(this.id); if (modelObj){ modelObj.foo(); } } } The event handler function will need to find the instance of myObj in order to invoke its foo() method. We provide a finder method: function getMyObj(id){ var key=id.split("_")[0]; return MyObjects[key]; } It has a reference to the DOM node and can use its id property to extract a key from which to retrieve the Model object from the global array. And there it is. The Reference Model By Name method served me well for a few years, and it works, but there is a simpler, cleaner way that doesn’t pepper your Licensed to jonathan zheng Methods and functions 613 DOM tree with lengthy IDs. (Actually, I never reached a decision as to whether that was good or bad. It was a waste of memory, for