Mark Eschbach

Software Developer && System Analyst

AngularJS 1.x

AngularJS is an opensource framework for developing complex applications in the browser tier. AngularJS's entire ecosystem is entirely agnostic of any service tiers you may desire to communicate with, and requires no connectivity to any remote trusted application layers. There are many promises of differences between AngularJS's 1.x series and the AngularJS 2.x series.

Articles

Testing
Notes on testing in AngularJS

Notes - To be expanded on later

  • AngularJS has several roles a component may be, all backed by a 'provider' for each role. Additional roles may be added by creating a new provider for the role. Roles:
    • Controller - JS control of the DOM manipulation of a given scope.
    • Service - Generall a single instance within the DI container, utilized for coordination/logic/(communication with external services).
    • Factory - Produces a instance of an object on demand. The factory function is provided by the DI container and must be invoked to produce.
    • Provider - Allows for the production of custom roles. May be used to build a plug-in subsystem for expandin components.
  • AngularJS provides bindings for the manipulation and customization of the DOM. Controller's are wired to the DOM via a $scope and directives. Directives are allow to manipulate the DOM based on modifications of the value the $scope. Effectively, at this layer, this is MVC with the following bindings: Controller (MVC) -> Directive (AngularJS), Model (MVC) -> $scope, View (MVC) -> DOM. I could be wrong here, and I'm interested in studying this further in the future. As usual with MVC, it only applies to a single layer of software. Once you begin adding layers then MVC is out of context and new architectures need to be used to discuss elements (MVVM, etc).
  • An approach to plugable templates with dynamic controllers: http://onehungrymind.com/angularjs-dynamic-templates/. Alternative: http://toddmotto.com/killing-it-with-angular-directives-structure-and-mvvm/. Decently complex applications require pluggable views; unforunately this is one setup AngularJS doesn't support this out of the box.

Configurable providers for plug-ins.

When building something like a dashboard, you quickly run into the problem of how to display data without common view factors. Generally, there is some metadata which needs to be associated with the type of data to be displayed. You really have two choices with this meta data: either have the dashboard depend on the views for teh dashboard, or invert the dependnecy and have the modules depend on the dashboard. With Angular, can esaily do this with configuring a service provider holding a registry of view.

angular.module( "application", [ "dashboard", "system-a", "system-b" ] )

angular.module( "dashboard", [] )
.provider( "PluginManager", function(){
	var plugins = {};
	this.register = function( id, plugin ){
		if( plugins[id] ) throw new Error( id + " is already registered");
		plugins[id] = plugin;
	}

	function PluginManager( plugins ){
		this.plugins = plugins;
	}
	PluginManager.internalize = function( widget ){
		return plugins[id]( widget );
	}

	this.$get = [ function PluginMangerFactory(){
		return new PluginManager( plugins );
	}];
})
.service( "DashboardHTTPGateway", [ "$http", function DashboardHTTPGateway( $http ){
	this.get_widgets = function(){
		return $http.get( "/dashboard", { headers: { 'Accepts' : 'application/example-dashboard-widgets' } })
		.then( function( data ){
			return data.widgets;
		});
	}
}])
.controller( "Dashboard", [ "PluginManager", "DashboardHTTPGateway", "$scope", function( plugins, dashboard, $scope ){
	$scope.state = 'loading';
	dashboard.get_widgets().then( function( widgets ){
		$scope.state = 'loaded';
		$scope.widgets = widgets.map( function( widget ){
			return plugins.internalize( widget.plugin );
		});
		//$scope.widgets applied to a series of ng-views using the 'template' property.
	});
}])
;

angular.module( "system-a", [] )
.config( [ "PluginManager", function( pluginManagerProvider ){
	pluginManagerProivder.register( 'widget-a', function(){
		return { template: "<section><h3>l;widget-a</h3></section>" };
	});
}]);

angular.module( "system-b", [] )
.config( [ "PluginManager", function( pluginManagerProvider ){
	pluginManagerProivder.register( 'widget-b', function(){
		return { template: "<section>widget-b with a fancy pants graph</section>" };
	});
}]);
		

Double transclusion

I think tabs are the easiest metaphor to use for expressing this problem domain, but definitely there are a lot more. Given a semantic element containing two components you wish to go into two different places on the DOM, what technique do you use to accomplish this?

  1. Transclude and move

    The general idea here is to implement the #link function within your directive and reparent the DOM elements to the correct template node. ( example is ref "Transclude in AngularJS" at header "Transclude at multiple locations" ).

    Positive
    • Easy to implement.
    • Subtrees will have the correct scoping automagically created.
    Negatives
    • Entire subtree is required to be travsered and categorized.
    • Seems wrong to reparent DOM nodes.
    • You can only shunt the existing nodes, not create multiple copies of the original component tree.
    • Temporary DOM node is created and removed soley for sorting elements.
Xref