Create vs. Get AngularJS application
The module dependency array tells AngularJS to create an app, otherwise to load it:
Create myApp | var app = angular.module('myApp', []); |
Get myApp | var app = angular.module('myApp'); |
Binding
-
@
Text binding, expressions are supported using{{ }}
=
Two-way binding&
Method binding<
One-way binding (usually for components)?
for an optional binding e.g.@?
for an optional string binding
Service, Factory, Provider, Value & Controller
- A
Service
is a singleton instance of a custom object. In can be used to share state or usually to wrap the remote REST API in a reuseable faction. It is injected using the name (review sample).
Basically simple AngularJs beans we want to inject later.
angular.module('myApp').service('myServiceName', ['depedency', function(depedency) { var privateState = {foo: 'bar'}; // this will be shared between any we inject this service this.publicApi = function(newConfig) { return privateState.foo; // shared singleton state }; }]);
- The
Factory
follows as the name already tells the factory pattern and so allows us to construct either a complexvalue
we want to inject into our controllers or even already existing JS objects which require any dependencies upfront. Basically wrap beans which need a constructor injection (review sample).
// any bean function myService($log) { this.log = $log; } myService.prototype.getState = function() { return this.state; // still shared if we like } //-- AngularJS starts here // construct the bean and inject what is needed angular.module('myApp', []).factory( 'myServiceFactory', ['$log', function($log) { // here is the main difference to service, // manually call new return new myService($log); }]);
Provider
- A
Provider
is the base forfactory
andservice
and has the biggest flexibility. Most important it can be injected into the config method and so configured before the first usage (review sample).
// my service / or just bean function myService($log, initValue) { this.log = $log; this.state = { foo: initValue || 'Default state' }; $log.info('Service Constructor called ...'); } myService.prototype.getState = function() { this.log.info('getState called ...'); return this.state; } // create angular myApp var myApp = angular.module('myApp', []); // register the provider providing our service // function name is here only to how that this is the provider myApp.provider('myService', function myServiceProvider() { // config area var providerState; this.config = function(newState) { providerState = newState; }; // constructor like in factory // again the name only indicates that here is where the factory function goes... this.$get = ['$log', function myServiceFactory($log) { return new myService($log, providerState); }] }); // configure the provider / service myApp.config(['myServiceProvider', function (myServiceProvider) { console.info('config:', myServiceProvider); myServiceProvider.config('configured state'); }]); // just use it myApp.component('c1', { controller: ['myService', function(myService) { this.state = myService.getState(); }], template: 'C1: <input ng-model="$ctrl.state.foo">' }); myApp.component('c2', { controller: ['myService', function(myService) { this.state = myService.getState(); }], template: 'C2: <input ng-model="$ctrl.state.foo">' });
- A
Value
is a simple object, int or string we want to make available for injection
HTML elements in AngularJS
Access HTML element Directive
The easiest way is just to use the link method:
angular.module('myApp).directive('myDirective', function () { return { restrict: 'A', replace : false, // scope, the element and the attributes link: function ($scope, element, attr) { // controller not needed if we have no public API } } }
Access HTML element in Component
In a component we can just inject the $element
.
jsui.component('myComponent', { // first we can always inject the element of the component controller: ['$element', function ($element) { var subEl = $element.find('.any-class'), // optional search by class rawDomEl = subEl[0]; // get the raw DOM element }); }], templateUrl: 'app/myTemplate.html' });
Access raw HTML element
As you can see in the last example we can access the raw DOM element using [0]
on the wrapped element.
Restrict in Angular Directive
The restrict
option is typically set to:
'A'
– only matches attribute name'E'
– only matches element name'C'
– only matches class name'M'
– only matches comment
These restrictions can all be combined as needed:
'AEC'
– matches either attribute or element or class name
URL Routing to AngularJS components
app.config(['$urlRouterProvider', '$stateProvider', function($urlRouterProvider, $stateProvider) { $urlRouterProvider.otherwise('/home'); .state('home', { url: '/home', component: 'homeComponent' }) }) // this could be in an own file .component('homeComponent', { controller: function () { // this.title is available console.info("homeComponent loaded ..."); }, templateUrl: 'home/home.html' }) ;
ocLazyLoad angular components during routing
As the lifecycle of components is a bit different we have to eager load them using ocLazyLoad:
.state('home', { url: '/home', component: 'homeComponent', resolvePolicy: { deps: { when: "EAGER" } }, // LOAD EAGERLY resolve: { deps: ['$ocLazyLoad', function ($ocLazyLoad) { return $ocLazyLoad.load( { // best to store it static somewhere if needed more than once ... name: "lazyHome", files: ["home/homeComponent.js"] } ); }] } });
Access URL parameters
The easiest way to access the URL params is just to inject $stateParams
into the component get read it. A bit cleaner is using the resolve
of the state
to inject the parameters into the component. As so we have to keep in mind that happens async, which means we have to implement the $onInit
method to get hold of the injected values into our component. More to components.
// given this state router we want to pass the vin to our component .state('app.vehicle', { url: '/vehicle/:vin', component: 'vehicleComponent', // pass the vin from the URL to the component resolve: { // could have the same name vehicleId: function($stateParams) { return $stateParams.vin; } } }) // component using the VIN, here string binding app.component('vehicleComponent', { bindings: { vehicleId: '@' }, // we could access state passing here function($stateParams) // and later with $stateParams.vin, which would couple URL id to components // and so we should better inject it ... controller: function () { // async called INIT method vinComponent is set this.$onInit = function() { console.info(this.vehicleId); }; // this is most likely not defined, as the resolve happens async console.info(this.vehicleId); }, templateUrl: 'vehicle.html' });
Dynamic ncyBreadcrumb label for AngularJS Components
Accessing just the $scope
doesn’t always work well during the reload of the page furthermore, it doesn’t work for components anyhow. The easiest way is just to inject the $breadcrumb
service and be done with it:
// state definition .state('app.customer', { url: '/customer/:customerId', component: 'customer', ncyBreadcrumb: { parent: 'app.customers', label: '{{ pageLabel || "New Customer" }}' } }); // in the component just assign the label attribute in the ncyBreadcrumb angular.module('myApp').component('customer', { bindings: { customerId: '@' }, controller: ['$breadcrumb', function ($breadcrumb) { // set the page label $breadcrumb.$getLastViewScope().pageLabel = "my page label"; }], templateUrl: 'customer.html' });
Thanks for sharing this.