- •preface
- •acknowledgments
- •about this book
- •Who should read this book?
- •Roadmap
- •Code conventions
- •Code downloads
- •Author Online
- •About the title
- •About the cover illustration
- •Rethinking the web application
- •A new design for the Web
- •1.1 Why Ajax rich clients?
- •1.1.1 Comparing the user experiences
- •1.1.2 Network latency
- •1.1.3 Asynchronous interactions
- •1.1.4 Sovereign and transient usage patterns
- •1.1.5 Unlearning the Web
- •1.2 The four defining principles of Ajax
- •1.2.1 The browser hosts an application, not content
- •1.2.2 The server delivers data, not content
- •1.2.3 User interaction with the application can be fluid and continuous
- •1.2.4 This is real coding and requires discipline
- •1.3 Ajax rich clients in the real world
- •1.3.1 Surveying the field
- •1.3.2 Google Maps
- •1.4 Alternatives to Ajax
- •1.4.2 Java Web Start and related technologies
- •1.5 Summary
- •1.6 Resources
- •First steps with Ajax
- •2.1 The key elements of Ajax
- •2.2 Orchestrating the user experience with JavaScript
- •2.3 Defining look and feel using CSS
- •2.3.1 CSS selectors
- •2.3.2 CSS style properties
- •2.3.3 A simple CSS example
- •2.4 Organizing the view using the DOM
- •2.4.1 Working with the DOM using JavaScript
- •2.4.2 Finding a DOM node
- •2.4.3 Creating a DOM node
- •2.4.4 Adding styles to your document
- •2.4.5 A shortcut: Using the innerHTML property
- •2.5 Loading data asynchronously using XML technologies
- •2.5.1 IFrames
- •2.5.2 XmlDocument and XMLHttpRequest objects
- •2.5.3 Sending a request to the server
- •2.5.4 Using callback functions to monitor the request
- •2.5.5 The full lifecycle
- •2.6 What sets Ajax apart
- •2.7 Summary
- •2.8 Resources
- •Introducing order to Ajax
- •3.1 Order out of chaos
- •3.1.1 Patterns: creating a common vocabulary
- •3.1.2 Refactoring and Ajax
- •3.1.3 Keeping a sense of proportion
- •3.1.4 Refactoring in action
- •3.2 Some small refactoring case studies
- •3.2.2 Managing event handlers: Observer pattern
- •3.2.3 Reusing user action handlers: Command pattern
- •3.2.4 Keeping only one reference to a resource: Singleton pattern
- •3.3 Model-View-Controller
- •3.4 Web server MVC
- •3.4.1 The Ajax web server tier without patterns
- •3.4.2 Refactoring the domain model
- •3.4.3 Separating content from presentation
- •3.5 Third-party libraries and frameworks
- •3.5.2 Widgets and widget suites
- •3.5.3 Application frameworks
- •3.6 Summary
- •3.7 Resources
- •Core techniques
- •The page as an application
- •4.1 A different kind of MVC
- •4.1.1 Repeating the pattern at different scales
- •4.1.2 Applying MVC in the browser
- •4.2 The View in an Ajax application
- •4.2.1 Keeping the logic out of the View
- •4.2.2 Keeping the View out of the logic
- •4.3 The Controller in an Ajax application
- •4.3.1 Classic JavaScript event handlers
- •4.3.2 The W3C event model
- •4.3.3 Implementing a flexible event model in JavaScript
- •4.4 Models in an Ajax application
- •4.4.1 Using JavaScript to model the business domain
- •4.4.2 Interacting with the server
- •4.5 Generating the View from the Model
- •4.5.1 Reflecting on a JavaScript object
- •4.5.2 Dealing with arrays and objects
- •4.5.3 Adding a Controller
- •4.6 Summary
- •4.7 Resources
- •The role of the server
- •5.1 Working with the server side
- •5.2 Coding the server side
- •5.2.1 Popular implementation languages
- •5.3 The big picture: common server-side designs
- •5.3.1 Naive web server coding without a framework
- •5.3.2 Working with Model2 workflow frameworks
- •5.4 The details: exchanging data
- •5.4.2 Introducing the planet browser example
- •5.5 Writing to the server
- •5.5.1 Using HTML forms
- •5.5.2 Using the XMLHttpRequest object
- •5.5.3 Managing user updates effectively
- •5.6 Summary
- •5.7 Resources
- •Professional Ajax
- •The user experience
- •6.1 Getting it right: building a quality application
- •6.1.1 Responsiveness
- •6.1.2 Robustness
- •6.1.3 Consistency
- •6.1.4 Simplicity
- •6.1.5 Making it work
- •6.2 Keeping the user informed
- •6.2.1 Handling responses to our own requests
- •6.2.2 Handling updates from other users
- •6.3 Designing a notification system for Ajax
- •6.3.1 Modeling notifications
- •6.3.2 Defining user interface requirements
- •6.4 Implementing a notification framework
- •6.4.1 Rendering status bar icons
- •6.4.2 Rendering detailed notifications
- •6.4.3 Putting the pieces together
- •6.5 Using the framework with network requests
- •6.6 Indicating freshness of data
- •6.6.1 Defining a simple highlighting style
- •6.6.2 Highlighting with the Scriptaculous Effects library
- •6.7 Summary
- •6.8 Resources
- •Security and Ajax
- •7.1 JavaScript and browser security
- •7.1.1 Introducing the “server of origin” policy
- •7.1.2 Considerations for Ajax
- •7.1.3 Problems with subdomains
- •7.2 Communicating with remote services
- •7.2.1 Proxying remote services
- •7.2.2 Working with web services
- •7.3 Protecting confidential data
- •7.3.1 The man in the middle
- •7.3.2 Using secure HTTP
- •7.3.3 Encrypting data over plain HTTP using JavaScript
- •7.4 Policing access to Ajax data streams
- •7.4.1 Designing a secure web tier
- •7.4.2 Restricting access to web data
- •7.5 Summary
- •7.6 Resources
- •Performance
- •8.1 What is performance?
- •8.2 JavaScript execution speed
- •8.2.1 Timing your application the hard way
- •8.2.2 Using the Venkman profiler
- •8.2.3 Optimizing execution speed for Ajax
- •8.3 JavaScript memory footprint
- •8.3.1 Avoiding memory leaks
- •8.3.2 Special considerations for Ajax
- •8.4 Designing for performance
- •8.4.1 Measuring memory footprint
- •8.4.2 A simple example
- •8.5 Summary
- •8.6 Resources
- •Ajax by example
- •Dynamic double combo
- •9.1 A double-combo script
- •9.2 The client-side architecture
- •9.2.1 Designing the form
- •9.2.2 Designing the client/server interactions
- •9.3 Implementing the server: VB .NET
- •9.3.1 Defining the XML response format
- •9.4 Presenting the results
- •9.4.1 Navigating the XML document
- •9.4.2 Applying Cascading Style Sheets
- •9.5 Advanced issues
- •9.5.2 Moving from a double combo to a triple combo
- •9.6 Refactoring
- •9.6.1 New and improved net.ContentLoader
- •9.7 Summary
- •Type-ahead suggest
- •10.1 Examining type-ahead applications
- •10.1.2 Google Suggest
- •10.2.1 The server and the database
- •10.3 The client-side framework
- •10.3.1 The HTML
- •10.3.2 The JavaScript
- •10.3.3 Accessing the server
- •10.5 Refactoring
- •10.5.1 Day 1: developing the TextSuggest component game plan
- •10.5.3 Day 3: Ajax enabled
- •10.5.4 Day 4: handling events
- •10.5.6 Refactor debriefing
- •10.6 Summary
- •11.1 The evolving portal
- •11.1.1 The classic portal
- •11.1.2 The rich user interface portal
- •11.2 The Ajax portal architecture using Java
- •11.3 The Ajax login
- •11.3.1 The user table
- •11.4 Implementing DHTML windows
- •11.4.1 The portal windows database
- •11.4.3 Adding the JS external library
- •11.5 Adding Ajax autosave functionality
- •11.5.1 Adapting the library
- •11.5.2 Autosaving the information to the database
- •11.6 Refactoring
- •11.6.1 Defining the constructor
- •11.6.2 Adapting the AjaxWindows.js library
- •11.6.3 Specifying the portal commands
- •11.6.4 Performing the Ajax processing
- •11.6.5 Refactoring debrief
- •11.7 Summary
- •Live search using XSLT
- •12.1 Understanding the search techniques
- •12.1.1 Looking at the classic search
- •12.1.3 Examining a live search with Ajax and XSLT
- •12.1.4 Sending the results back to the client
- •12.2 The client-side code
- •12.2.1 Setting up the client
- •12.2.2 Initiating the process
- •12.3 The server-side code: PHP
- •12.3.1 Building the XML document
- •12.3.2 Building the XSLT document
- •12.4 Combining the XSLT and XML documents
- •12.4.1 Working with Microsoft Internet Explorer
- •12.4.2 Working with Mozilla
- •12.5 Completing the search
- •12.5.1 Applying a Cascading Style Sheet
- •12.5.2 Improving the search
- •12.5.3 Deciding to use XSLT
- •12.5.4 Overcoming the Ajax bookmark pitfall
- •12.6 Refactoring
- •12.6.1 An XSLTHelper
- •12.6.2 A live search component
- •12.6.3 Refactoring debriefing
- •12.7 Summary
- •Building stand-alone applications with Ajax
- •13.1 Reading information from the outside world
- •13.1.1 Discovering XML feeds
- •13.1.2 Examining the RSS structure
- •13.2 Creating the rich user interface
- •13.2.1 The process
- •13.2.3 Compliant CSS formatting
- •13.3 Loading the RSS feeds
- •13.3.1 Global scope
- •13.3.2 Ajax preloading functionality
- •13.4 Adding a rich transition effect
- •13.4.2 Implementing the fading transition
- •13.4.3 Integrating JavaScript timers
- •13.5 Additional functionality
- •13.5.1 Inserting additional feeds
- •13.5.2 Integrating the skipping and pausing functionality
- •13.6 Avoiding the project’s restrictions
- •13.6.1 Overcoming Mozilla’s security restriction
- •13.6.2 Changing the application scope
- •13.7 Refactoring
- •13.7.1 RSS reader Model
- •13.7.2 RSS reader view
- •13.7.3 RSS reader Controller
- •13.7.4 Refactoring debrief
- •13.8 Summary
- •The Ajax craftsperson’s toolkit
- •A.1 Working smarter with the right toolset
- •A.1.1 Acquiring tools that fit
- •A.1.2 Building your own tools
- •A.1.3 Maintaining your toolkit
- •A.2 Editors and IDEs
- •A.2.1 What to look for in a code editor
- •A.2.2 Current offerings
- •A.3 Debuggers
- •A.3.1 Why we use a debugger
- •A.3.2 JavaScript debuggers
- •A.3.3 HTTP debuggers
- •A.3.4 Building your own cross-browser output console
- •A.4 DOM inspectors
- •A.4.1 Using the Mozilla DOM Inspector
- •A.4.2 DOM inspectors for Internet Explorer
- •A.4.3 The Safari DOM Inspector for Mac OS X
- •A.5 Installing Firefox extensions
- •A.6 Resources
- •JavaScript for object-oriented programmers
- •B.1 JavaScript is not Java
- •B.2 Objects in JavaScript
- •B.2.1 Building ad hoc objects
- •B.2.2 Constructor functions, classes, and prototypes
- •B.2.3 Extending built-in classes
- •B.2.4 Inheritance of prototypes
- •B.2.5 Reflecting on JavaScript objects
- •B.2.6 Interfaces and duck typing
- •B.3 Methods and functions
- •B.3.1 Functions as first-class citizens
- •B.3.2 Attaching functions to objects
- •B.3.3 Borrowing functions from other objects
- •B.3.4 Ajax event handling and function contexts
- •B.3.5 Closures in JavaScript
- •B.4 Conclusions
- •B.5 Resources
- •Ajax frameworks and libraries
- •Accesskey Underlining Library
- •ActiveWidgets
- •Ajax JavaServer Faces Framework
- •Ajax JSP Tag Library
- •Ajax.NET
- •AjaxAC
- •AjaxAspects
- •AjaxCaller
- •AjaxFaces
- •BackBase
- •Behaviour
- •Bindows
- •BlueShoes
- •CakePHP
- •CL-Ajax
- •ComfortASP.NET
- •Coolest DHTML Calendar
- •Dojo
- •DWR (Direct Web Remoting)
- •Echo 2
- •FCKEditor
- •Flash JavaScript Integration Kit
- •Google AjaxSLT
- •Guise
- •HTMLHttpRequest
- •Interactive Website Framework
- •Jackbe
- •JPSpan
- •jsolait
- •JSON
- •JSRS (JavaScript Remote Scripting)
- •LibXMLHttpRequest
- •Mochikit
- •netWindows
- •Oddpost
- •OpenRico
- •Pragmatic Objects
- •Prototype
- •Qooxdoo
- •RSLite
- •Ruby on Rails
- •Sack
- •SAJAX
- •Sarissa
- •Scriptaculous
- •SWATO…
- •Tibet
- •TinyMCE
- •TrimPath Templates
- •Walter Zorn’s DHTML Libraries
- •WebORB for .NET
- •WebORB for Java
- •XAJAX
- •x-Desktop
- •XHConn
- •index
- •Symbols
- •Numerics
606APPENDIX B
JavaScript for object-oriented programmers
subgroups, this trust inevitably weakens. If you want to add a few checks and balances to your code on top of duck typing, then perhaps this section will have shown you where to start.
We’ve looked at the language from the point of view of objects. Now let’s drill down a little to look at these functions that we’ve been throwing around and see what they really are.
B.3 Methods and functions
We’ve been defining functions and calling them in the previous section and in the rest of this book. A Java or C# programmer might have assumed that they were something like a method, defined with a slightly funny-looking syntax. In this section, we’ll take functions apart a bit more and see what we can do with them.
B.3.1 Functions as first-class citizens
Functions are a bit like Java methods in that they have arguments and return values when invoked, but there is a key difference. A Java method is inherently bound to the class that defined it and cannot exist apart from that class. A JavaScript function is a free-floating entity, a first-class object in its own right. (Static Java methods lie somewhere in between these two—they are not bound to any instance of an object but are still attached to a class definition.)
Programmers who have worked their way through the C family may think “Ah, so it’s like a function pointer in C++, then.” It is indeed, but that’s not the end of it.
In JavaScript, Function is a type of built-in object. As expected, it contains executable code, and can be invoked, but it is also a descendant of Object, and can do everything that a JavaScript object can, such as storing properties by name. It is quite possible (and quite common) for a Function object to have other Function objects attached to it as methods.
We’ve already seen how to get a reference to a Function object. More usually, we would want to reference a function and invoke it in a single line, such as
var result=MyObject.doSomething(x,y,z)
However, the Function is a first-class object, and it can also be executed via the call() method (and its close cousin apply()):
var result=MyObject.doSomething.call(MyOtherObject,x,y,z)
or even
Methods and functions |
607 |
|
|
var result=MyObject['doSomething'].call(MyOtherObject,x,y,z)
The first argument of Function.call() is the object that will serve as the function context during the invocation, and subsequent arguments are treated as arguments to the function call. apply() works slightly differently in that the second argument is an array of arguments to pass to the function call, allowing greater flexibility in programmatically calling functions whose argument list length is undetermined.
It’s worth pointing out here that the argument list to a JavaScript function is not of a fixed length. Calling a Java or C# method with more or fewer arguments than it declares would generate a compile-time error. JavaScript just ignores any extra args and assigns undefined to missing ones. A particularly clever function might query its own argument list through the arguments property and assign sensible defaults to missing values, throw an exception, or take any other remedial action. This can be exploited to combine a getter and setter method into a single function, for example:
function area(value){ if (value){
this.area=value;
}
return this.area;
}
If we simply call area(), then value is undefined, so no assignment takes place, and our function acts as a getter. If a value is passed in, our function acts as a setter. This technique is used extensively by Mike Foster’s x library (see the Resources section at the end of this chapter, and also chapter 3), so if you plan on working with that, you’ll soon be familiar with the idiom.
Functions become really interesting, though, when we take advantage of their independence as first-class objects.
B.3.2 Attaching functions to objects
As a functional language, JavaScript allows us to define functions in the absence of any object, for example:
function doSomething(x,y,z){ ... }
Functions can also be defined inline:
var doSomething=function(x,y,z){ ... }
As a concession to object-orientation, functions may be attached to objects, giving the semblance of a Java or C# method. There is more than one way of doing this.
608APPENDIX B
JavaScript for object-oriented programmers
We can attach a predefined function to a predefined object (in which case only that object can call the function, not any other object derived from the same prototype):
myObj.doSomethingNew=doSomething;
myObj.doSomethingNew(x,y,z);
We can also attach functions such that every instance of a class can access them, by adding the function (either predefined or declared inline) to the new object in the constructor, as we saw in section B.2.2, or by attaching it to the prototype.
Once we’ve done this, though, they aren’t very strongly attached, as we will see.
B.3.3 Borrowing functions from other objects
Giving functions first-class object status alters the capabilities of a language significantly. Furthermore, an understanding of these alterations is important when coding GUI event handling, so most Ajax programmers would do well to understand it.
So what are these new capabilities? Well, first off, one object can borrow another’s function and call it on itself. Let’s define a class to represent species of tree in a taxonomic system:
function Tree(name, leaf, bark){ this.name=name; this.leaf=leaf; this.bark=bark;
}
Next, we’ll add a function to it that provides a quick description of the tree:
Tree.prototype.describe=function(){
return this.name+": leaf="+this.leaf+", bark="+this.bark;
}
If we now instantiate a Tree object and ask it to describe itself, we get a fairly predictable response:
var Beech=new Tree("green, serrated edge","smooth"); alert(Beech.describe());
The alert box will display the text Beech: leaf=green, serrated edge, bark=smooth. So far, so good. Now let us define a class to represent a dog:
function Dog(name,bark){ this.name=name; this.bark=bark;
}
Methods and functions |
609 |
|
|
and create an instance of our Dog class:
var Snowy=new Dog("snowy","wau! wau!");
Snowy wants to show us his bark, but, although we’ve defined it for him, he has no function through which to express it. He can, however, hijack the Tree class’s function:
var tmpFunc=Beech.describe; tmpFunc.call(Snowy);
Remember, the first argument to function.call() is the context object, that is, the object that the special variable this will resolve to. The previous code will generate an alert box displaying the text Snowy: leaf=undefined, bark=wau! wau!. Well, it’s better than nothing for the poor dog.
So what’s going on here? How can a dog call a function that really belongs to a tree? The answer is that the function doesn’t belong to the tree. Despite being peppered with references to this, assigning the function to the Tree prototype binds it only inasmuch as it enables us to use the shorter MyTree.describe() notation. Internally, the function is stored as a piece of text that gets evaluated every time it is called, and that allows the meaning of this to differ from one invocation to the next.
Borrowing functions is a neat trick that we can use in our own code, but in production-quality code, we’d prefer to see someone implement a bark() method for Snowy of his very own. The real reason for discussing this behavior is that when you are writing event-handling code, the web browser will do it for you behind the scenes.
B.3.4 Ajax event handling and function contexts
Ajax event handlers are pretty much the same as most GUI toolkit languages, with specialized categories for mouse and keyboard events, as we saw in chapter 4. Our example uses the onclick handler, fired when a mouse is clicked on a visible element. A full discussion of DHTML event handling is beyond the scope of this book, but let’s take the time here to highlight a particular issue that can often trip up the unwary.
Event handlers can be declared either as part of the example
<div id='myDiv' onclick='alert:alert(this.id)'></div>
or programmatically; for example:
610APPENDIX B
JavaScript for object-oriented programmers
function clickHandler(){ alert(this.id); } myDiv.onclick=clickHandler;
Note that in the programmatic case, we pass a reference to the Function object (that is no () after the clickHandler). When declaring the function in the HTML, we are effectively declaring an anonymous function inline, equivalent to
myDiv.onclick=function(){ alert(this.id); }
Note that in both cases, the function has no arguments assigned to it, nor is there any way for us to pass in arguments with the mouse click. However, when we click on the DOM element, the function is called with an Event object as the argument and the element itself as the context object. Knowing this can save a lot of grief and puzzlement, particularly when you’re writing object-based code. The key source of confusion is that the DOM node is always passed as context, even if the function is attached to the prototype of a different object.
In the following example, we define a simple object with an event handler for a visible GUI element that it knows about. We can think of the object as the Model in MVC terms, with the event handler taking the role of Controller, and the DOM element being the View.
function myObj(id,div){ this.id=id; this.div=div;
this.div.onclick=this.clickHandler;
}
The constructor takes an internal ID and a DOM element, to which it assigns an onclick handler. We define the event handler as follows:
myObj.prototype.clickHandler=function(event){
alert(this.id);
}
So, when we click on the GUI element, it will alert us to the ID of that object, right? 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
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 |
|
Global lookup |
1. Resolve this.id and |
|
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.
612APPENDIX 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
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 sure, but it also made debugging in the Mozilla DOM Inspector very easy.)
Attaching a Model to the DOM node
In this second approach to DOM event handling, everything is done with object references, not strings, and no global lookup array is needed. This is the approach that has been used throughout this book. Figure B.2 illustrates this approach.
This approach simplifies the event handler’s job considerably. The constructor function for the Model object needs no specialized ID manipulation, and the foo() method is defined as before. When we construct DOM nodes, we exploit JavaScript’s dynamic ability to attach arbitrary attributes to any object and clip the Model object directly onto the DOM node receiving the event:
myObj.prototype.createView=function(){
...
this.body=document.createElement("div");
this.body.modelObj=this;
...
this.titleBar=document.createElement("div");
this.titleBar.modelObj=this;
this.titleBar.onclick=fooEventHandler;
...
}
When we write the event handler, we can then get a direct reference back to the Model:
Model object
DOM element
2.Resolve this.modelObj
1. Resolve this
Event handler
Figure B.2
Attaching a reference to the Model directly to a DOM node makes it easier for the event handler function to find the Model at runtime.