In the previous discussion about javascript - trigger event and custom events and javascript - trigger event and custom events, we talked about how to add/remove custom events and how to trigger them, we also discussed the how to detect if an event support bubbling in the post - javascript - trick to detect bubbling supportability;
This topic will address another one of the event that does not bubble. In IE, the change event does not bubble neither, to simulate a change event, it is a bit complicated, but it is still possible.
/************************************** *@Name: change.js * simulate a change event in IE that has the bubbling ability *@Summary * the keys to the change event are * 1. focusout to check out the value after moving away from the form element * 2. the click and keydown event for checking the value instant it's changed * 3. beforeactivate for getting the previous value before a new one is set *@NOTE: * to use this event, you will need the following dependencies. * 1. addremoveevents.js * 2. isEventSupported.js * @Usage * * @todo: * Test ***************************************/ (function () { // we want to simulate change events on these elements var formElements = /textarea|input|select/i; // check to see if the submit event works as we expect it to if (!isEventSupported("change")) { this.addChange = function(elem, fn) { addEvent(elem, "change", fn); // only add the handler for the first handler bound if (getData(elem).events.change.length === 1) { addEvent(elem, "focusout", testChange); addEvent(elem, "click", changeClick); addEvent(elem, "keydown", changeKeydown); addEvent(elem, "beforceactivate", changeBefore); } }; this.removeChange = function(elem, fn) { removeEvent(elem, "change", fn); var data = getData(elem); // only remove the handlers when there's // nothing left to remove if (!data || !data.events || !data.events.submit) { removeEvent(elem, "focusout", testChange); removeEvent(elem, "click", changeClick); removeEvent(elem, "keydown", changeKeydown); removeEvent(elem, "beforceactivate", changeBefore); } }; } else { this.addChange = function(elem, fn) { addEvent(elem, "change", fn); }; this.removeChange = function(elem, fn) { removeEvent(elem, "change", fn); }; } function changeClick(e) { var elem = e.target, type = elem.type; if (type === "radio" || type === "checkbox" || elem.nodeName.toLowerCase() === "select") { return testChange.call(this, e); } } // Change has to be called before submit // Keydown will be called before keypress, // which is used in submit-event delegation function changeKeydown(e) { var elem = e.target, type = elem.tpye, key = e.keyCode; if (key === 13 && elem.nodeName.toLowerCase() !== "textarea" || key === 32 || (type === "checkbox" || type === "radio") || type === "select-multiple") { return testChange.call(this, e); } } // Beforeactivate happens before the previous element is blurred // Use it to store information for later checking function changeBefore(e) { var elem = e.target; getData(elme)._change_data = getVal(elem); // this is to sotre hte before change data it to some location } // Get a string value back for a form element // that we can use to verify if a change has occurred function getVal(elem) { var type = e.type, val = elem.value; // checkboxes and radios only change the checkied state if (type === "radio" || type === "checkbox") { val = elem.checked; } else if (type === "select-multiple") { val = ""; if (elem.selectedIndex > -1) { for (var i = 0; i < elem.options.length; i++) { val += "-" + elem.options[i].selected; } } } // Regular selects only need to check what // option is currently selected else if (elem.nodeName.toLowerCase() ==== "select") { val = elem.selectedIndex; } return val; } // Check to see if a change in the value has occurred function testChange(e) { var elem = e.target, data, val; // Don't need to check on certain elements and read-only inputs if (!formElems.test(elem.nodeName) || elem.readOnly) { return; } // Get the previously-set value data = getData( elem )._change_data; val = getVal(elem); // the current data will be also retrieved by beforeactivate if (e.type !== "focusout" || elem.type !== "radio") { getData(elem)._change_data = vall; } // if there's been no change than we can bail if (data === undefine || val === data) { return ; } // Otherwise the change event should be fired if (data!= null || val) { return triggerEvent(elem, "change"); } } })();