AJAX In Action [194]
via code that looks similar to the HTML in listing 10.21.
Listing 10.21 TextSuggest HTML markup
Licensed to jonathan zheng 398 CHAPTER 10 Type-ahead suggest The implication of this HTML is that we’re going to construct our object with the ID of the text field we will be attaching to, the URL for the Ajax data source, and a set of configuration objects yet to be specified. (Note that the text field needs an ID attribute for this to work properly.) Everything inside the Listing 10.22 TextSuggest constructor TextSuggest = Class.create(); TextSuggest.prototype = { initialize: function(anId, url, options) { this.id = anId; b Reference the this.textInput = $(this.id); input element var browser = navigator.userAgent.toLowerCase(); this.isIE = browser.indexOf("msie") != -1; c Detect the this.isOpera = browser type browser.indexOf("opera")!= -1; this.suggestions = []; this.setOptions(options); d Set the defaults this.initAjax(url); this.injectSuggestBehavior(); }, ... }; Now let’s deconstruct the constructor. As already mentioned, we pass into our constructor the ID of the text input to which we’ll be attaching the suggest Licensed to jonathan zheng Refactoring 399 behavior. A reference is held to both the ID and the DOM element for the input field b. Next we do a little browser sniffing and store the state for the few things in the rest of the component that need to know specifics about the browser runtime environment c. In this case, special case code is needed only for IE and Opera, so we sniff only for them. We’ll discuss the complex part of setting up Ajax and injecting behavior later d. Let’s concentrate for the rest of the day on component configurability. As you recall, earlier we created a SetProperties() function to hold all of the configurable aspects of our suggest script: function SetProperties (xElem, xHidden, xserverCode, xignoreCase, xmatchAnywhere, xmatchTextBoxWidth, xshowNoMatchMessage, xnoMatchingDataMessage, xuseTimeout, xtheVisibleTime){ ... } This meets the requirement of providing configurability but not of providing a convenient API or appropriate defaults. For this, we introduce an options object that is passed into the constructor. The options object has a property for each configuration parameter of the suggest component. Let’s now fill in the options with some configuration parameters: var suggestOptions = { matchAnywhere : true, ignoreCase : true }; function injectSuggestBehavior() { suggest = new TextSuggest( 'field1', 'typeAheadXML.aspx', suggestOptions ); } ); This simple idiom comes with a big-time payload: ■ It keeps the signature of the constructor clean. The client pages using our component can construct it with only three parameters. ■ Configuration parameters can be added over time without changing the contract of the constructor. ■ We can write a smart setOptions() that provides appropriate default values for any unspecified properties, allowing the caller to specify only the properties that she wants to override. Licensed to jonathan zheng 400 CHAPTER 10 Type-ahead suggest The last bullet is exactly what the d setOptions() method shown earlier in the constructor