First baby steps with Angular.js
This article outlines some of my notes of a webinar about Angular.js I recently participated at. These are really just “baby steps” in that it covers the very basics that might help to get started. Since these are really my first steps with Angular, I might have misunderstood some of the stuff. So feel free to help me improve this article ;)
Info: the source code of some of the examples described here can be found on the GitHub repo.
The App
ng-app
represents the angular application. ng-app="myApp"
does normally have a corresponding
angular.module('myApp', []);
in some JavaScript file.
Data Binding
{{}}
are placeholders in HTML that are being interpreted by Angular. Similar as in other popular templating engines like Mustache. It only represents a unidirectional binding though.
ng-init="text=Hello World"
allows to introduce variables. After such a declaration you can reference text
and its value.
<div ng-init='text='Hello World''> <p>Value: {{ text }}</p> </div>
If we want to achieve bidirectional bindings then we have to use ng-model
.
<input ng-model='text'/>
Controllers
As one would assume, controllers are responsible for a certain HTML area they are bound to.
<body ng-controller='MyController'> <p>{{ welcomeMessage }}</p> </body
angular.module('myApp') .controller('MyController', ['$scope', function($scope){ $scope.welcomeMessage = 'Hi, welcome to the Angular tutorial'; $scope.sayHello = function(name){ alert('Hi ' + name); }; }]);
Filters
What is quite handy on the output is that there are lots of filters available that allow you to customize it, like reversing the output:
{{ welcomeMessage | reverse }}
Pipes (|
) are used to apply the filter to some value. You can also combine several once (just like unix pipes). There are predefined ones on the official docs for predefined ones and custom ones like our reverse filter above. Implementing it is quite simple:
angular.module('myApp') // factory function .filter('reverse', function (){ // directly return a function return function(text){ text = '' + text; // execute reversing return text.split('').reverse().join(''); } });
Events and Services
Similarly as simply binding values you can also attach click handlers like
<body ng-controller='MyController'> <input type='text' ng-model='name' /> <button ng-click='sayHello(name)'>Say Hello</button> </body>
Note how the databound variable name
can be directly passed to the sayHello(..)
function.
angular.module('myApp') .controller('MyController', ['$scope', function($scope){ $scope.welcomeMessage = 'Hi, welcome to the Angular tutorial'; $scope.sayHello = function(name){ alert('Hi ' + name); }; }]);
In order to not fill up the controller with lots of logic, you should extract them in re-usable services.
angular.module('myApp') .factory('MyGreetingService', function(){ return { sayHello: function(name){ alert('Hi ' + name); } }; });
The above construct represents a factory method for creating the service which is uniquely identified by MyGreetingService
. Note that services are singletons.
On the controller you then inject the service as follows:
angular.module('myApp') .controller('MyController', ['$scope', 'MyGreetingService', function($scope, greetingService){ ... $scope.sayHello = function(name){ // invoke the service greetingService.sayHello(name); }; }]);
Variables prefixed by $
are those provided by Angular.
Directives
Another powerful concept of Angular are directives. They aim at bringing web components to you, augmenting the HTML with custom elements.
<hello-world></hello-world>
The <hello-world>
is implemented as follows:
angular.module('myApp') // the name of the directive defines the final HTML tag that // has to be used. .directive('helloWorld', function(){ return { restrict: 'E', //E=Element, A=attribute, C=css class or combined EAC //template: '<p>Hello, world!</p>', //inline specification templateUrl: 'helloWorldPartial.html' //load from HTML file } });
The restrict
property specifies the kind of element, whether it is a HTML element, an attribute or CSS class. You can also mix more of them.
The rendered template can be either specified inline using the template
property or in a separate file, using templateUrl
. The latter one is the suggested way especially when you have more complex HTML code.
Note: HTML isn’t case sensitive and as such also custom HTML tags should not be written in camel case but rather be separated by a dash.
If you want to get a deep-dive into how directives work I absolutely suggest you Misko Hevery’s meetup video.
Structuring and Modules
An Angular module is defined like
angular.module('myApp', []);
This example code shows the definition of the application in myApp.js
. While there is no restriction on how an Angular application should be structured, a module/widget structure is suggested. Hence, rather than organizing your app in controllers
, models
and views
folder…
..structure it according to the functionalities or modules, like calculator
, contacts
etc., depending on the kind of application you’re creating.
I did already write about such modularity in JavaScript MVC applications.
In my example code I have an app that contains a “calculator” module. The folder structure looks like
- <calculator> - calculatorController.js - calculatorService.js - index.js
The index.js
defines the module:
angular.module('calculator', []);
Each of the other files like the controller and service have to be defined within that module.
angular.module('calculator') .controller('CalculatorController',...
Finally, myApp
needs to load the module (in myApp.js
):
angular.module('myApp', [ 'calculator' ]);
What’s kind’a odd is that although CalculatorController
is defined within the calculator
module, you don’t have to prefix it in the HTML code:
<div ng-controller='CalculatorController'>...</div>
Wait, this might get tricky and lead to potential name clashes when including multiple modules. Yep, and it seems like currently this is the solution:
As of today AngularJS doesn’t handle namespace collisions for services so if you’ve got 2 different modules with the service named the same way and you include both modules in your app, only one service will be available.
For the moment the best option is to prefix service names with a custom prefix… StackOverflow
Where’s jQuery?
Can I use it? Angular uses a lite version of jQuery. The suggested approach is to avoid using jQuery directly and go as far as you can by using directives, controllers and live binding. However, jQuery can obviously be included. If so, you need to include it before the angular.js script include.
<head> <script type='text/javascript' src='jQuery.js'></script> <script type='text/javascript' src='angular.js'></script> ... </head>
Angular will detect it and use the included jQuery version rather than its own lite version of it.
Generally speaking the use of jQuery should dramatically decrease due to live binding and Angular directives.
There’s a lot more…
This article really just covers what was covered in the webinar. There’s a lot more that has to be taken a look at in order to create a fully featured single page application like routing, views, unit testing…
Question to the speaker
Here are two questions I posed to the speaker.
You mentioned about using Angular directives sparingly. Why?
- Not use directives for everything, but just where it makes sense, i.e. when you create a list with a simple filter you might be better served by simply using a controller.
- Not due to performance issues
- directives for having reusable HTML elements (web components)
What would be the “model” of M-VC in Angular?
There isn’t a model like it may be known from other frameworks. The “model” of Angular is somehow the combination of $scope
, the data binding and the services if we wish..
Angular uses more a MVVM variation of the classic MVC.
Useful Links
- https://angularjs.org/
- https://docs.angularjs.org/api/ng/service
- https://docs.angularjs.org/tutorial
- https://docs.angularjs.org/api
- https://docs.angularjs.org/guide
- http://angularjs.de/
- StackOverflow obviously ;)
- Angular Design Patterns best practices
- Angular.js in Patterns
Info: the source code of some of the examples described here can be found on the GitHub repo.
Reference: | First baby steps with Angular.js from our WCG partner Juri Strumpflohner at the Juri Strumpflohner’s TechBlog blog. |