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");
}
}
})();