AngularJS Design (Obsolete)
Items of note:
John Papa's style recommendations steer you in a good direction:
- Use self-executing module (Immediately Invoked Function Expression — or IIFE)
- Declare dependencies using the $inject syntax.
- 'use strict'
- var for the module and then declare the module's dependencies
- module.config to handle navigation ($routeProvider). This also names a controller.
- The controller is referred to in the config, and defined in a module.controller call. This has its list of dependencies
*
Example of Module declarations referring to Functions
angular .module('crNetEdit.recs', ['crNetEdit.LocModule','ui.bootstrap']) .controller('RecSelectController', RecSelectController) .service('newNodeService', newNodeService) .directive('crRecSelect', crRecSelect) ; RecSelectController.$inject = [ '$scope', 'LocResource', 'NetworkRefresh', 'newNodeService'];
NOTE: Capitilization still needs to be sorted out.
Service Accessing Root Scope
I've got a few cases where the Service is bound to elements in the root scope of the module. Here's some tips on implementing this.
- Think of a Service as something that connects models. Include them within a module that exposes the "view model" to directives where views can bind to the model.
- Services are not injected with scope: http://stackoverflow.com/questions/22898927/injecting-scope-into-an-angular-service-function. You can however, bind the results of a service to a scope.
- Preferred binding is via the isolate scope.
- The Service will have a local ("private") var that holds the results provided by the service (populating some object typically).
- The Service will return a method that returns the local copy.
- The Service will update that local copy when it is called to provide its data.
- Inside the controller for the overall app, declare a dependency on the service.
- Also inside the controller for the overall app, extend the root scope with the "global" element that is to be shared.
- Invoke the before-mentioned method on the service that returns the local copy and assign it to the $scope element being shared.
Examples
- One example is the NetworkRefresh.segments() service and method. It uses a method that returns a local copy of the data setup by the module.
- Another example is the RecSelectModule which binds to the external scope using an attribute on a Directive.
Binding Notes
- View Model is used to expose the elements which are visible outside the module. These are the "public" elements.
- Regular 'var' objects are used for the private elements that are shared amongst the functions and services within the module.
- The View Model is bound using the controllerAs syntax. vm is the canonical name for the object whose dotted properties are the public "API".
- In the HTML where the directive is brought in, there is an attribute which names an element in the scope. In the RecSelect example, the cr-rec-select Directive is in the splitMaps.html file and refers to the scope using the 'network' attribute. This attribute refers to the element in scope 'gjNetwork'.
- The module's controller (not the directive's controller, although I could explore this once again) makes the connection between the View Model and the public elements within the Module.
- Specifically, the internal variable representing the externally bound object(s) will be found using the $scope.$parent.<attrName>.
NOTE
It is likely that since
a) a Service is a singleton
b) the sharing of the data may as well be the sharing of the Service
that we could dispense with keeping a copy of the data in the Root Scope and only use the copy that is declared within the Service. Need to explore that.
Weak Spots & Gaps
- Capitilization for constructors
- Other naming conventions
- Dotted notation for "namespace"
- filenames
- Handling of promises from Resources
- The binding is still a little shaky.
page revision: 4, last edited: 10 May 2019 20:34