ng-binder

- by Wesley Pumpkinhead on 25-09-2015

Basic assimilation of AngularJS's two-way data-binding using JQuery.

JavaScript

$(document).ready(function(){

	var myApp = {
		propA: "",
		propB: ""
	};
	
	var propNames = Object.keys(myApp);
	$(propNames).each(function(k, v){
		var ngBinderAttr = "[ng-binder=" + v + "]";
		var domBinders = $(ngBinderAttr);
		$(domBinders).each(function(i, el){
			if($(el).is("input,textarea")){
				$(el).on("keyup", function(){
					// update object property with value from input field
					myApp[$(this).attr("ng-binder")] = $(this).val();
					// update any other elements with the same "ng-binder" value
					var ngBinderAttr = "[ng-binder=" + $(this).attr("ng-binder") + "]";
					var domBinders = $(ngBinderAttr);
					$(domBinders).each(function(i, ele){
						if(el !== ele){ // don't waste resources updating the element that fired the event
							ele.textContent = myApp[$(this).attr("ng-binder")];
							ele.value = myApp[$(this).attr("ng-binder")];
						};
					});
				});
			};
		});
	});
	
	function ngReBinder(){
		var propNames = Object.keys(myApp);
		$(propNames).each(function(k, v){
			var ngBinderAttr = "[ng-binder=" + v + "]";
			var domBinders = $(ngBinderAttr);
			$(domBinders).each(function(i, el){
				$(el).val(myApp[v]);
				$(el).text(myApp[v]);
			});
		});
	};
	
	// -------------------------------------------------------
	// watch for DOM changes in "myApp" childNodes
	// -------------------------------------------------------
	// NOTE: New "ng-binder" elements that are added to DOM
	// later will only show their "bound" value when a keyup event
	// is fired on another element with the same ng-binder value.
	// The ngReBinder() function solves that problem by
	// re-initialising the text and values of all ng-binder
	// elements to their application property values
	// ----------------------------------------------------------
	var observer = new MutationObserver(function(mutations){					
		mutations.forEach(function(mutation){
			// changes to DOM detected
			// re-bind/initialise all ng-binders to application property values!
			ngReBinder();
		});
	});
	observer.observe($("[ng-application=myApp]")[0], {attributes:true, childList:true, characterData:true});
	
	// reset (empty) all INPUT elements when page loads
	var inputEls = $(":input");
	$(inputEls).each(function(){
		this.value = "";
	});
	
	// add new ng-binder DIVs to myApp DOM
	$(propNames).each(function(i, prop){
		$('#addNgBinder_' + prop).on("click", function(){
			var div = $("<div ng-binder='" + prop + "'></div>");
			var row = $("<div class='row'></div>");
			var col = $("<div class='col'></div>");
			$(row).append(col);
			$(col).append(div);
			$($("[ng-application=myApp]")[0]).prepend(row);
		});
	});
});