Recently I came across AngularJS – a javascript framework to boost productivity of front-end development.
They have this awesome tutorial where you can download code from Github and they guide you through a sequence of steps. Very well done.
When I finished it I was missing something though. I still didn’t know how to create reusable components using Angular.
After a little bit of research, I found out that it’s not missing from Angular, it’s just missing from the tutorial.
So I made two pull requests (step-12 and step-13) to their repo. I hope they add that to their tutorial (well, they would probably need to improve it a bit first).
I’ll try to explain here how the code works:
I’m assuming you have already tried the official tutorial yourself, in other words, you have cloned their repo and played a bit with it.
You can go ahead and clone QMagico’s forked angular-phonecat repo, and checkout into branch step-12.
The open http://localhost:8000/app/using_components.html
You’ll see two sets of pictures, with their thumbnails that you can click to view a larger image.
Here’s the code for app/using_components.html:
<!doctype html> <html lang="en" ng-app="using_components" ng-controller="UsingComponentsCtrl"> <head> <meta charset="utf-8"> <title>Google Phone Gallery</title> <link rel="stylesheet" href="css/app.css"> <link rel="stylesheet" href="css/bootstrap.css"> <script src="lib/angular/angular.js"></script> <script src="js/using_components.js"></script> <script src="js/services.js"></script> <script src="lib/angular/angular-resource.js"></script> </head> <body> <phoneimages phone="phone1"></phoneimages> <br><br><br><br><br><br><br><br><br><br> Who bought this, also bought <br><br><br> <phoneimages phone="phone2"></phoneimages> </body> </html>
That <phoneimages> tag is the custom component.
The attributes phone1 and phone2 are two variables defined in the controller $scope, in js/using_components.js.
Here’s the code for it:
'use strict'; /* App Module */ angular.module('using_components', ['phonecatServices']) function UsingComponentsCtrl($scope, Phone) { $scope.phone1 = Phone.get({phoneId: 'nexus-s'}); $scope.phone2 = Phone.get({phoneId: 'motorola-xoom'}); }
In this file we’re defining both the module (which is called “using_components”) and the controller.
In other words, the file using_components.js is playing the role of app.js and controllers.js in the previous steps.
Our module depends on phonecatServices, which is defined in js/services.js
Here’s the code:
'use strict'; /* Services */ angular.module('phonecatServices', ['ngResource']). factory('Phone', function($resource){ return $resource('phones/:phoneId.json', {}, { query: {method:'GET', params:{phoneId:'phones'}, isArray:true} }); }).directive('phoneimages', function() { return { restrict: 'E', scope:{ phone:'=phone' }, templateUrl: 'partials/phoneimg.html', controller: function ($scope) { $scope.imgindex = 0 $scope.setIndex = function(index) { $scope.imgindex = index; } } }; });
There you can see the already familiar Phone service factory, and we also have something new: The phoneimages directive.
That’s our custom component. This is what angular will use to build our component when it encounters the <phoneimages> tag.
What the code means:
- restrict: ‘E’ – means that our component is a html element
- scope:{phone:’=phone’} – means that our component $scope will have a ‘phone’ variable, binded to whatever is passed in the ‘phone’ attribute
- templateUrl – The html code that Angular will use to render this component
- controller: function($scope){…} – This component javascript behaviour
The last piece of code missing is the html template: partials/phoneimg.html:
<div> <img ng-src="{{phone.images[imgindex]}}" class="phone"> <h1>{{phone.name}}</h1> <p>{{phone.description}}</p> <ul class="phone-thumbs"> <li ng-repeat="img in phone.images" ng-click="setIndex($index)"> <img ng-src="{{img}}"> </li> </ul> </div>
There you have it. A “images with clickable thumbnails” component, where the click-to-enlarge behaviour is encapsulated away from the client.
This is a very powerful feature of AngularJS.
Now that you understand Angular components, take a look at this short video to learn how to use transclusion to nest components:
I’ve used Backbone, but wanted to try other Javascript MVC frameworks too. I think AngularJS is one that a lot of people has been using lately. Thanks for the short introduction.
In phonecatServices, line 10, you define a directive and pass the name of the custom element. Could you instead use something like a CSS selector?
> Could you instead use something like a CSS selector?
I still don’t have the answer to that. I’ll come back here if I find out!
Hey Tony, very nice tutorial, thanks for sharing it!