Search code examples
javascriptprototypejs

Event listening with event action exclusion


I have a change event on an input that I want to be triggered except when you click on a list item. Basically I call a function to check this field when its changed, however there is also an autocomplete script on this that adds an unordered list just below the input that you select from, which triggers the change when you click an item to populate the input field (which essentially triggers before the new value is added). Here is the javascript code:

document.observe('dom:loaded',function() { 
    new Ajax.Autocompleter("search_input", "found_input", "someurl.jsp", {
        afterUpdateElement: updateSelectedItem,
        minChars: 2
    });
    if ($('search_input') != undefined) {
        $('search_input').observe('change', function(e, el) {
            if (e.explicitOriginalTarget.up(1) != undefined && e.explicitOriginalTarget.up(1).id != "found_input") {
                checkFunction(this.value);
            }
        });
    }
});

I added the explicitOriginalTarget in there as it works in Mozilla browsers, but that is not a cross browser solution. I also tried adding a variable that gets added when you click an unordered list item, but that gets triggered after the search_input field as it comes after it in the DOM.

Thanks for the assistance.

EDIT:

You can see a little example here: http://jsfiddle.net/DfMYE/5/ If you start to type in 'test', you will see a drop down of 2 options. When you click on one, it triggers the change event and the select event. I want to stop the change event if we click on the select list.


Solution

  • Here's my admittedly hackish solution: http://jsfiddle.net/kkFsJ/1/

    What's happening is that by clicking on an autocomplete option, you're blurring the input field, therefore committing whatever value you typed and the change event is dispatched on the field. This is all before you you're able to click (which requires mouseup) on the autocomplete option to trigger that functionality to replace the input content with what you chose. This is the root of your problem.

    What I don't fully understand is why after you make your autocomplete selection, another change event doesn't get called (at least in Safari). I wonder if programmatically changing an input's value doesn't trigger the change event. I should probably know if that's the case or not, but I'd need to test it. Any ideas?

    So - what I did was subclass the Autocompleter.Local class and assigned the onClick callback to each li's mousedown event. This seems to trigger onClick before the form's blur event (and therefore firing change). I then manually fire a change event on the input field.

    I still had to set a changing flag so that the searchHandler callback didn't get called multiple times for a single autocomplete selection. This was happening in Firefox. I defer the actual working of this callback to let the events settle down, then turn the changing flag back off. This is the grossest part, sorry.

    One thing to note is that if you choose an autocomplete option, a change event will always get fired, regardless of whether or not chosen the value is different than what was originally in the input field. Avoiding that would take more tinkering with the Autocompleter code which I'll let you take care of if you want. Also, I've only tested this out in FF and Safari on a Mac, so test and tweak things out appropriately if this is going to production.

    Hopefully this works out or at least gives you some ideas. If you or anyone else has a different take on this problem (besides rewriting the autocompleter functionality), I'd love to hear.