Skip to content

Instantly share code, notes, and snippets.

@msacket
Last active August 10, 2021 03:18
Show Gist options
  • Save msacket/85c85716ea4ef1f9416e8b06cf0ebc9c to your computer and use it in GitHub Desktop.
Save msacket/85c85716ea4ef1f9416e8b06cf0ebc9c to your computer and use it in GitHub Desktop.

Leverage Angular without Starting from Scratch

There are days in a life that emerge as stand outs amongst the rest. Some of those days are expected; a wedding perhaps or the birth of a child. Others happen without fanfare. The day I found Angular was one of those days.

I was in the midst of working on the Arch LMS. It had become laborious. The UI I had envisioned was becoming a mess of ajax calls glued together with jQuery. It worked, but it was fragile. That wasn't really jQuery's fault. I used it for something it wasn't meant to do and tracking all those events was impossible.

Seeking something else, I found myself watching a presentation on Knockout. Not bad. It did lead me to Underscore.js, but for some reason it wasn't clicking for me. Perhaps if I'd given it more time. Still, I thought there had to be a better way. Then I found Angular.

Maybe it was because of my background in WebObjects, but the idea of creating directives (components in wo-speak) on the client side was exciting. And all those directives need to work, was a bit of json. Lovely. After 16 years, Web development could be fun again.

I wanted to scrap the whole application and start from scratch, but quickly realized I couldn't. That would take too long and there was too much to do. Instead, I had to find a way to begin incorporating Angular immediately, while keeping my existing codebase intact.

My existing application utilized a lot of document level events that I could trigger from any page with click handlers. I simply passed the required options through those. For example:

// main script
$(document).on('edit-plan', function(e, options){
	// edit the lesson plan with options.id
});

// somewhere else, perhaps the lesson plans page
$('.edit-plan').click(function(e){
	e.preventDefault(); 
	$(document).trigger('edit-plan', {
		id: $(this).data('id')
	});
});

All I needed to do to begin using Angular was tap into the edit-plan event. Already using RequireJS, I wrote a function that allowed me to inject a module into the dom and bootstrap it. Here is the function:

/**
 * xg-bootstrap.js
 *
 * Injects an Angular module into the DOM asynchronously and returns a promise 
 * to resolve when the injection is complete. 
 */ 
define(['angular'], function(angular) {
	return function(app, appEl, $selector){ 
		var d; 
		angular.injector(['ng']).invoke(['$q', function($q){ 
			d = $q.defer(); 
			angular.element($selector || 'body').append(appEl); 
			angular.bootstrap(appEl, [app.name]);
			d.resolve({ 
				'app': app, 
				'appEl': appEl, 
				'scope': appEl.scope() 
			}); 
		}]); 
		return d.promise;
	}; 
});

I could then create a module or mini-app unencumbered by any other dependencies and inject it like this:

// mods/alert/app.js
define(['angular', 'libs/xg-bootstrap', 'text!mods/alert/template.html'], function(angular, xgBootstrap, template){
	return function module(){
		var appEl = angular.element(template);
		var app = angular.module('AlertApp', []);
		app.controller('AlertAppCtrl', ['$scope', '$sce', function($scope, $sce){
			$scope.message = "";
			$scope.close = function(){
				appEl.remove();
			};
			$scope.$watch('message', function(){
				$scope.messageHtml = $sce.trustAsHtml($scope.message);
			});
		}]);
		return xgBootstrap(app, appEl);
	};
});
<div class="xg-modal">
	<div class="xg-alert"><button ng-click="close()">Close</button></div>
</div>

And to invoke the app:

// main.js 
$(document).on('alert', function(event, options){ 
	requirejs(["mods/alert/app"], function(module){ 
		var promise = new module(); 
		promise.then(function(app){ 
			app.scope.$apply(function(){ 
				app.scope.message = options.message; 
			});
		}); 
	}); 
});
// within some html page 
$('#alert-button').click(function(event){ 
	event.preventDefault(); 
	$(document).trigger('alert', { 
		message: "À tout le monde, hello." 
	}); 
});

So that's what I did, one by one replacing my jQuery-based dialogs and code with Angular based ones. I was able to immediately use Angular, while moving forward with the application. And it was fun.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment