Script.aculous, Autocompleter, Element.collectTextNodes and Element.cleanWhitespace

A couple days ago I was fighting with the Script.aculous autocompleter. I was using code that was almost exactly like the customized autocompletion demo, where the content returned from the AJAX call was a bulleted list of items with each item containing three div’s:

<ul id="mylist">
  <li>
    <div><img src="/images/avatar/robot.png" /></div>
    <div>Aaron Johnson</div>
  </li>
  <li>
  ...
  </li>
</ul>

After the content is returned, the user selects an option and the ‘updateElement()’ function of Autocompleter.Base is called, which itself uses a function ‘Element.collectTextNodes()’. Element.collectTextNodes traverses the all the nodes in the selected option and retrieves the text value of each one, effectively stripping the HTML from the ul element. Finally, the autocompleter takes the resulting text value and updates the value of the textbox that you started with in the first place.

At least that’s what’s supposed to happen. What actually happened was that the textbox wasn’t showing the selected value at all and I beat my head against my desk a couple times. Why? If you take the HTML example above and run it through Element.collectTextNodes(), you’ll get this:


Aaron Johnson

not this:

Aaron Johnson

See the line break? If you try to update the value of a textbox with a variable whose first line is a line break, the textbox sees only the line break and nothing else.

The solution turns out to be a widely used function in prototype: Element.cleanWhitespace(), which removes all empty text node children of an element. So I updated Element.collectTextNodes to look like this:

Element.collectTextNodes = function(element) {
  element = Element.cleanWhitespace(element);
  return $A($(element).childNodes).collect( function(node) {
    return (node.nodeType==3 ? node.nodeValue :
      (node.hasChildNodes() ? Element.collectTextNodes(node) : ''));
  }).flatten().join('');
}

I created a wiki page on the script.aculous wiki for the Element.collectTextNodes function, post a comment on the wiki if you agree that the function should include a call to Element.cleanWhitespace.

This entry was posted in JavaScript. Bookmark the permalink.

2 Responses to Script.aculous, Autocompleter, Element.collectTextNodes and Element.cleanWhitespace

  1. Chris says:

    I ran into the exact same issue as well on my blog at http://functionalruby.com/articles/2006/08/19/text_field_with_auto_complete-and-whitespace

    My solution was sorta stupid, but I just changed the reply string to not have new lines in it. It’s a workaround versus your real fix, but it worked, and I moved on.

  2. Ashwin says:

    Aaron,

    When the user makes a selection, I want the contents inside the element to be copied *verbatim* to the linked text box. I believe the relevant code is located in controls.js employing Element.collectTextNodes to perform the copy. I have some HTML embedded into each list item, which must be included in the copy – not just text. How do you advice I go about this?

    Thanks.

    Ashwin

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>