var app = angular.module('RoutingDemoApp', []);
The second parameter (in this example an empty array) is not optional: it's where additional modules (i.e., dependencies) that your app module will use are specified. You'll almost certainly want to put this JS in a separate file, say, ''app.js''.
The resulting not-doing-anything-interesting-yet files might look like:
This is my home page. Fascinating, isn't it?
Enough about me. Let's talk about you. What do you think of me?
function uselessController() {
console.log('yawn.');
}
This works but messes with the global namespace and supposedly has other issues (e.g., with minification FIXME ref?). It also offends my sense of modularity.
Another way is to define it using the app's ''controller'' method:
demoApp.controller('uselessController', function () {
console.log('yawn.');
});
I can tolerate that.
You tell the ''$routeProvider'' about a controller by setting the ''controller'' property for a route to a //string// that is the name of the controller:
...
when('/', {
controller: 'uselessController',
templateUrl: 'views/bored.html'
})
...
==== $scope ====
Controllers are almost always passed an AngularJS magical object called ''$scope''. ''$scope'' is the glue between controllers and templates: whatever is contained within the ''$scope'' object after the controller completes execution will be available to the template.
Here is a new ''app.js'' where the root route is associated with a controller called ''homeController''. In the controller, we set a property on ''$scope'' called ''name''. That chunk of data will be available for use in the template.
This is my home page. Fascinating, isn't it?
This is my home page. Fascinating, isn't it?
.
├── index.html
├── js
│ └── app.js
├── lib
│ └── angularjs
│ ├── angular.min.js
│ └── angular-route.min.js
└── views
├── about.html
├── contact.html
└── home.html
'Nuff said.
==== Template directives ====
AngularJS provides some directives that allow you to implement control-flow-like structures in your templates. A common one is ''[[https://docs.angularjs.org/api/ng/directive/ngRepeat|data-ng-repeat]]'', which works as an iterator:
// file app.js
...
when('/fruit', {
controller: 'fruitController',
templateUrl: 'views/fruit.html'
}).
...
// Create a collection of fruits on $scope.
demoApp.controller('fruitController', function ($scope) {
$scope.fruits = [
{name: "apple", isSweet: true},
{name: "tomato", isSweet: false},
{name: "strawberry", isSweet: true},
{name: "avocado", isSweet: false}
];
});
...
A list of sweet fruits
- {{fruit.name}}
Got apple?
- {{fruit.name}}
...
Other ones worth noting include ''[[https://docs.angularjs.org/api/ng/directive/ngSwitch|data-ng-switch]]'',
''[[https://docs.angularjs.org/api/ng/directive/ngHide|data-ng-hide]]'', and
''[[https://docs.angularjs.org/api/ng/directive/ngShow|data-ng-show]]''.
==== Template filters ====
Another way you can do some lightweight processing and formatting of data in the template is by using filters. They can be applied to both AngularJS data attributes (i.e., ''%%data-ng-the-thing-you-want-filter | filter-name : filter-parameters
A common application is sorting, which can be achieved with the ''[[https://docs.angularjs.org/api/ng/filter/orderBy|orderBy]]'' filter:
- {{fruit.name}}
Here, we add an ''[[https://docs.angularjs.org/api/ng/filter/uppercase|uppercase]]'' filter to the ''fruit.name'' interpolation to make it yell (because you should be eating more fruit):
- {{fruit.name | uppercase}}
In addition to ''[[https://docs.angularjs.org/api/ng/filter/orderBy|orderBy]]'' and
''[[https://docs.angularjs.org/api/ng/filter/uppercase|uppercase]]'', there are filters for formatting ''[[https://docs.angularjs.org/api/ng/filter/currency|currency]]'',
formatting ''[[https://docs.angularjs.org/api/ng/filter/date|date]]''s,
converting JavaScript objects into ''[[https://docs.angularjs.org/api/ng/filter/json|JSON]]'',
making content ''[[https://docs.angularjs.org/api/ng/filter/limitTo|limitTo]]'' a particular size,
converting strings to ''[[https://docs.angularjs.org/api/ng/filter/lowercase|lowercase]]'',
formatting a ''[[https://docs.angularjs.org/api/ng/filter/number|number]]'', and
a pretty powerful filter named ''[[https://docs.angularjs.org/api/ng/filter/filter|filter]]'' that lets you select a subset of items from array against some rather flexible matching criteria. And (I am lead to believe) you can create your own filters.
Filters can be chained if you want to apply more than one filter at a time:
A sorted list of sweet fruits
- {{fruit.name}}
...
when('/fruit/:fruitname', {
controller: 'fruitDetailController',
templateUrl: 'views/fruitDetail.html'
}).
...
A colon in front of a token in the path indicates that it is a parameter.
Next, the controller. You can access the parameters passed in the route by using another of AngularJS's magical objects: ''$routeParams''. It, like ''$scope'', needs to be passed to the controller if you want to use it:
demoApp.controller('fruitDetailController', function ($scope, $routeParams) {
var fruitname = $routeParams.fruitname;
// In a real app, I would do something really smart to generate
// the data you want about fruitname and then put that data into
// $scope. But for now, I'm going to be very lazy:
$scope.fruit = {
name: fruitname,
link: "https://lmddgtfy.net/?q=" + fruitname
};
});
And finally, the template---where there's nothing really new:
I don't know that much about the {{fruit.name}}. But these people probably do.
...
when('/:foodtype/:foodname', {
controller: 'foodDetailController',
templateUrl: 'views/food-detail.html'
}).
...
demoApp.controller('foodDetailController', function ($scope, $routeParams) {
var type = $routeParams.foodtype,
name = $routeParams.foodname;
// Still being lazy:
$scope.food = {
type: type,
name: name,
link: "https://lmddgtfy.net/?q=" + type + ' ' + name
};
});
I don't know that much about the {{food.type}} called {{food.name}}. But these people probably do.
myApp.factory('sillyFactory', function () {
var factory = {}; // TODO: Is the name 'factory' magical here?
factory.getCarter = function () {
return 'Carter';
};
factory.getShorty = function () {
return 'Shorty';
};
factory.getAll = function () {
return ['Carter', 'Shorty', 'Smart'];
};
return factory;
});
To use a factory in a controller, you need to inject it---here as the second parameter in the controller definition:
myApp.controller('someController', function ($scope, sillyFactory) {
$scope.leFoo = sillyFactory.getCarter();
});
Note that factories know nothing of ''$scope'', controllers. or templates. Nice and clean.
In the following, we have rewritten the ''fruitController'' to use a ''fruitFactory''. The only upside to this complication for now is that the fruits in the factory can be shared with other controllers. Ultimately the associated data doesn't have to be hard-coded; it might come from an API call or database or elsewhere.
// file app.js //
...
demoApp.controller('fruitController', function ($scope, fruitFactory) {
// Get some fruit from the factory:
$scope.fruits = fruitFactory.gimmieFruit();
});
...
demoApp.factory('fruitFactory', function () {
var factory = {},
fruitList; // the data of interest.
// Some dummy data:
fruitList = [
{name: "apple", isSweet: true},
{name: "tomato", isSweet: false},
{name: "strawberry", isSweet: true},
{name: "avocado", isSweet: false}
];
// Public methods
factory.gimmieFruit = function () {
return fruitList;
};
return factory;
});
==== Service ====
A service is similar to a factory except there is no intermediate object:
// file app.js //
...
demoApp.controller('fruitController', function ($scope, fruitService) {
// Get some fruit from the service:
$scope.fruits = fruitService.gimmieFruit();
});
...
demoApp.service('fruitService', function () {
var fruitList; // the data of interest.
// Some dummy data:
fruitList = [
{name: "apple", isSweet: true},
{name: "tomato", isSweet: false},
{name: "strawberry", isSweet: true},
{name: "avocado", isSweet: false}
];
// Public methods
this.gimmieFruit = function () {
return fruitList;
};
});
I'm not going to cover and values and providers (for now?).
The factory and service we created above are very simplistic. In a more typical app, you would put methods for doing [[wp>https://en.wikipedia.org/wiki/Create,_read,_update_and_delete|CRUD]] operations into your factories and services. All we've done so far is some primitive "R". To do "C", "U", and "D", it will help a thing or two about data binding.
===== Data binding =====
TODO
===== AJAX and APIs =====
TODO
===== Additional modularization =====
TODO
===== Conclusion =====
{{ :angularjs:icehockey.png?nolink |}}
That's about it for this short tour of the short end of AngularJS's hockey stick. There's tons more to explore. Get your [[https://www.google.com/#q=angularjs|Google]] (or [[https://duckduckgo.com/?q=angularjs|Duck]]) on and go for it.
===== Resources =====
The official [[https://docs.angularjs.org/api|AngularJS API documentation]] can be a bit confounding, but it's indispensable.
I found [[https://www.youtube.com/channel/UCtbxTmNfHcXLV5nfpnQxFkw|Dan Wahlin]]'s //AngularJS in 60-ish minutes// and [[https://www.youtube.com/user/howardjeremyp|Jeremy Howard]]'s //AngularJS end-to-end web app tutorial// video series helpful introductions.
Apparently, [[https://egghead.io/|egghead.io]] is really good for expanding your knowledge of the framework with short, highly focused videos.
I've got a copy of Green and Seshadri's //[[http://shop.oreilly.com/product/0636920028055.do|AngularJS]]//, but apart from looking at the table of contents, I haven't read it.
All images used here save that of Derek Zoolander and the AngularJS logo are in the public domain.
----
Copyright © 2014 [[http://mithatkonar.com|Mithat Konar]]. All rights reserved.