Why reinvent the wheel?
I personally like to implement all of my JS from scratch, I try to stay away from using the likes of jQuery or any external sources/libraries/frameworks as much as possible. Why? you may ask, the answer is simple, I want to learn how to do as much as possible with plain/vanilla JavaScript.
I understand that for real world implementations, it's probably best to use frameworks or libraries when you can, just to save development time, I'm more than aware of that, as they say.
Question
I understand that AngularJS implements two way data binding very well, however, I'd like to know how Angular implements two way data binding?
Is there a more efficient way to implement two way data binding?
Research
So far the best way of implementing data binding is doing it like what I've written below in the code example, however, I can't help but feel that there's a more efficient way of implementing such a feature, I find that there's possibly a more sophisticated way to implement the callback function that I've written below.
Code
I'm not sure what you all think of the code I've just written below, but it's simple enough, maybe not the best solution in the world, but that's fine because I'm trying to find a better solution is possible.
/**
* @description the purpose of this object is to encapsulate event handling
*/
function EventHandlerObject() {
// basic singleton implementation
if (EventHandlerObject.instance !== null && typeof EventHandlerObject.instance !== "undefined") {
return EventHandlerObject.instance;
} else {
EventHandlerObject.instance = this;
}
}
/**
* @description the purpose of this method is to add an event handler to a given dom object
* @param {Element||Array[Element]} obj
* @param {String} eventType
* @param {Function} callback
* @param {Boolean} bool
*/
EventHandlerObject.prototype.addEvent = function (obj, eventType, callback, override) {
if (typeof obj === "undefined" || obj === null) { return; }
if (typeof callback !== "function") { return; }
// a collection/aray/list of elements has been passed in
if (obj.length || obj instanceof Array) {
for (var i = 0, s = obj.length; i < s; i++) {
var elm = obj[i];
if (override === true) { // override all other events
this.remEvent(obj, eventType, callback);
}
try { // try to add the event and callback
if (elm.addEventListener) {
elm.addEventListener(eventType, callback, false);
} else if (elm.attachEvent) {
elm.attachEvent('on' + eventType, callback);
} else { elm["on"+eventType] = callback; }
} catch (e) { console.log(e); }
}
// a single element has been passed in
} else {
if (override === true) { // override all other events
this.remEvent(obj, eventType, callback);
}
try { // try to add the event and callback
if (obj.addEventListener) {
obj.addEventListener(eventType, callback, false);
} else if (obj.attachEvent) {
obj.attachEvent('on' + eventType, callback);
} else {
obj["on"+eventType] = callback;
}
} catch (e) {
console.log(e);
}
}
};
/**
* @description the purpose of this function is to remove an event handler from a given element
* @param {Element||Array[Element]} obj
* @param {String} eventType
* @param {Function} callback
*/
EventHandlerObject.prototype.remEvent = function (obj, eventType, callback) {
if (typeof obj === "undefined" || obj === null) { return; }
if (typeof callback !== "function") { return; }
// a collection/aray/list of elements has been passed in
if (obj.length || obj instanceof Array) {
for (var i = 0, s = obj.length; i < s; i++) {
var elm = obj[i];
try { // try to remove the event
if (elm.removeEventListener) {
elm.removeEventListener(eventType, callback, false);
} else { elm[eventType + callback] = null; }
} catch (e) { console.log(e); }
}
// a single element has been passed in
} else {
try { // try to remove the event
if (obj.removeEventListener) {
obj.removeEventListener(eventType, callback, false);
} else { obj[eventType + callback] = null; }
} catch (e) { console.log(e); }
}
};
/**
* @description the purpose of this function is to call the two above functions
* when necessary
* @param {Element||Array[Element]} obj
* @param {Array[String]} eventType
* @param {Function} callback
* @param {Boolean} bool
*/
EventHandlerObject.prototype.multiEvent = function (obj, eventType, callback, override) {
if (typeof obj === "undefined" || obj === null) { return; }
if (typeof callback !== "function") { return; }
if (!eventType.length) { return; }
if (override === true) { // override all other events
for (var i = eventType.length - 1; i > - 1; i --) {
this.remEvent(obj, eventType[i], callback);
}
}
// add multiple events
for (var i = eventType.length - 1; i > - 1; i--) {
this.addEvent(obj, eventType[i], callback);
}
};
// just a demo of the above code
var inp = document.getElementById("demoInput");
var out = document.getElementById("demoOutput");
var events = new EventHandlerObject();
// just do both as a demo
events.multiEvent(inp, ["keyup", "keydown", "keypress"], function() { out.textContent = inp.value; });
<input type="text" id="demoInput" />
<div id="demoOutput"></div>
remEvent
function? \$\endgroup\$ – Blindman67 Feb 19 '18 at 17:38