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.

2 thoughts on “Script.aculous, Autocompleter, Element.collectTextNodes and Element.cleanWhitespace”

  1. 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 to Ashwin Cancel reply

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