CodeSchool - Shaping up with Angular.JS
References
https://docs.angularjs.org/api
Overview
Angular is a client-side JavaScript framework for adding interactivity to HTML. We add behaviour to the HTML using directives
.
Directives : a marker on an HTML tag that tells Angular to run or reference some JavaScript code.
Modules : Encapsulates separate pieces of an Angular application, and defines dependencies.
app.js : var app = angular.module('store', [])
index.html : <html ng-app="store">
Runs this module when the document loads. The HTML inside the element with the ng-app
tag then gets treated as an Angular app.
Expressions
: Insert dynamic values into your HTML e.g. I am {{4 + 6}}
, {{"hello" + " you"}}
Controllers : Define application behaviour by defining functions and values
app.controller('StoreController', function() {
this.product = gem;
});
var gem = {...} // js object
- Enclose all JavaScript inside an enclosure to be safe. e.g.
(function() { [code here] })();
- Controller names are always in CapitalCase and use the word Controller.
- Specify the name of the controller and an anonymous function (the constructor).
product
is a property of the controller.- Use the
ng-controller
directive to attach the controller to an HTML element.
<div ng-controller="StoreController as store">
<h1></h1>
</div>
Built-In Directives
ng-app
ng-controller
ng-show
Element will be shown if the expression is true e.g. <button ng-show="store.product.isInStock">Add to Cart</button>
ng-hide
Element will not be shown if the expression is true e.g. <div ng-hide="store.product.isInStock"> ... </div>
ng-repeat
Use to iterate over an array e.g. <div ng-repeat="product in store.products"> ... </div>
ng-src
Images cannot be used via the <img src="expression">
method, since the browser will try to load the image before the expression is evaluated. Instead use the ng-src
directive. e.g. <img ng-src="" />
ng-click
Is evaluated when an element is clicked on. This can be used to change the page when someone clicks on certain elements. This is an example of two-way data binding. e.g. <a ng-click="product.selectTab(1)">product 1</a>
ng-init
Lets you initialise variables to an initial value. e.g. <div ng-init="tab = 1"
>
NOTE: great for prototyping, but is usually handled inside a controller.
ng-class
Apply the specified css class tag to an element if the expression evaluates to true.
<li ng-class="{ active:tab === 1 }">
ng-model
Binds the HTML element value to a property, so you can have two way binding e.g. type in one field and see the contents written to another field. Initialise any variables being used either with ng-init
or better still using a property of a controller.
ng-submit
Call a function when a form is submitted. e.g. ng-submit="reviewCtrl.addReview(product)"
ng-include
Extract commonly included HTML snippets into separate files. e.g. <h3 ng-include="'product-title.html'"></h3>
will insert the contents of the file product-title.html
inside the <h3>
tags. ng-include
expects a variable, so to pass in a file name instead, be sure to use single quotes.
Since this file won't be loaded until it is requested via ajax, it will be missing when the page initially loads. Instead of using ng-include
a custom directive can be used instead.
Filters
Often used in the form: ``
- ``
MM\dd\yyyy @ h:mma
- ``
- `` (use the -ve sign to indicate descending order)
Forms
- Add
novalidate
to the<form>
tag to turn off HTML validations. - Add
required
attributes to any fields which are mandatory. nameOfForm.$valid
is a special property which indicates if the form is currently valid or not. AND this value with the method called to submit the form, to ensure this method is never called if the form is not valid.ng-pristine
,ng-dirty
,ng-invalid
,ng-valid
are classes which are automatically applied to form fields and can be used to style them according to whether they are valid / invalid.- Use the
type
attribute to indicate which type of field it is e.g.type="email"
,type="url"
,type="number"
Custom Directives
Template-expanding directives are the simplest - they define a custom tag or attribute which is expanded or replaced (can contain Controller logic if needed). e.g. <product-title></product-title>
Directives can also be used for:
- Expressing complex UI
- Calling events and registering event handlers
- Reusing common components
app.directive('productTitle', function() {
return {
// A configuration object defining how your directive will work
restrict: 'E',
templateUrl: 'product-title.html'
};
});
- The HTML version
product-title
translates to the camelCase versionproductTitle
in JavaScript - Don't use self-closing tags with custom elements, some browsers don't like them
- Use Element directives for UI widgets and Attribute directives for mixin behaviours, like a tooltip.
Using controllers inside custom directives
Inside the app.directive
function definition, use the controller
attribute to specify the controller constructor functionality. Then use the controllerAs
attribute to specify the alias for the controller.
app.directive('productTitle', function() {
return {
// A configuration object defining how your directive will work
restrict: 'E',
templateUrl: 'product-title.html',
controller: function() {
},
controllerAs: 'panels'
};
});
Services
Angular comes with several built in services e.g. $http
to fetch JSON data from a web service, $log
to log messages to the script console, $filter
an array using the filter service.
$http
can either be used as a function itself, specifying all attributes internally OR use one of the shortcut methods e.g. $http.get
. Both methods return a Promise
object. which allows you to do callbacks on it e.g. .success()
or .error()
To use a service, use the service name as the first item in an array, and then pass this service in to the controllers constructor method. This is implicit Dependency Injection.
app.controller('SomeController', ['$http', function($http) {
}]);
app.controller('SomeController', ['$http', '$log', function($http, $log) {
}]);
When Angular loads it creates something called an Injector
. When the built-in services load, they register with the Injector as being available libraries. Then when our application loads, it registers the controller with the Injector, telling it that when it gets executed, it is going to need the $log
and $http
services. When the page loads and the controller gets used, the Inject grabs the services the controller needs and passes them in as arguments.
app.controller('StoreController', ['$http', function($http) {
this.products = ???;
$http.get('/products.json').success(function(data) {
??? = data;
});
}]);
In the code above, if we try to assign the data to this.products, it will fail, since this
inside the service is $http
. Instead, we need to capture the controller (this
) in a variable and use this in the success callback method. Initialise products to an empty array, so that when the page loads there won't be errors.
app.controller('StoreController', ['$http', function($http) {
var store = this;
store.products = [];
$http.get('/products.json').success(function(data) {
store.products = data;
});
}]);