Angularjs – A Hands On tutorial31 min read

Angularjs – A Hands On tutorial

This is a hands on tutorial on Angularjs.  We will walk through most of the key features of Angular, and by the end we will build an Angular application named Movie Stub.

You can see the live demo of the app here.

Preview:

Screen Shot 2014-03-14 at 9.01.49 PM Screen Shot 2014-03-14 at 9.02.11 PM Screen Shot 2014-03-14 at 9.02.28 PM Screen Shot 2014-03-14 at 9.02.36 PMSo, lets get started.

Contents

Code for each topic is available here. And the complete application code can be found here.

Angularjs

What

AngularJS is a structural framework for dynamic web apps. It lets you use HTML as your template language and lets you extend HTML’s syntax to express your application’s components clearly and succinctly. Angular’s data binding and dependency injection eliminate much of the code you currently have to write. And it all happens within the browser, making it an ideal partner with any server technology.

Why

HTML is great for declaring static documents, but it falters when we try to use it for declaring dynamic views in web-applications. AngularJS lets you extend HTML vocabulary for your application. The resulting environment is extraordinarily expressive, readable, and quick to develop.

You can read more about the “W”s of Angularjs here.

Create an Angularjs Boilerplate [code]

To make this hands on session result in a more “re-usable” product, we will start off by creating a template. And in future if you want to create a new Angular project, you can reuse this template.

We are creating an Online Movie Ticket Booking website named movieStub. The architecture is pretty simple. We will have Nodejs & Expressjs as our server side components. Angularjs as our client side component along with Bootstrap for a pleasant UI.

Now, Create a new folder with the name movieStub. Next open Prompt/Terminal inside the movieStub folder. First we need to setup node, more details here. Next, We will init a new node project, run npm init. Hit return if you don’t want to fill any field (the default values will get applied). This will generate a package.json file, which should look something like

Even though this is a Angularjs tutorial, I thought it would not hurt anyone to learn a bit of server side. So, we will be using a Node server to server our static page. We are going to let express handle server side stuff for us. If you are not aware of express, you can check out this post & come back or else, you can copy paste the code from here to continue. To add express to our project, run npm install express --save-dev This will save express as a dev dependency to our project.

Next, we will setup bower. If you don’t have bower package manager already installed, you can install by running the following commands

Windows Mac/*nix
npm install -g bower    sudo npm install -g bower

Next, we will init a new bower file to track our dependencies. Run bower init You can do the same thing as npm init. And the final file should look something like

Lets install Angularjs & add it to our project. Run bower install angular --save-dev Next, we need to add Twitter Bootstrap to our project. Run bower install bootstrap --save-dev Next, create a new folder at the root and name it public.  Our folder structure should be like Screen Shot 2014-03-11 at 8.54.00 PM

  • Head to bower_components/bootstrap/dist and copy css,fonts & js folders to the public folder.
  • We will split our javascript files into 2 pieces. create a folder inside the js folder & name it lib.
  • Copy the contents of js folder inside the lib folder.
  • Copy angular.min.js from bower_components/angular to public/js/lib folder & jquery.min.js from  bower_components/jquery/dist to public/js/lib folder
  • Create a new file and name it index.html inside the public folder.

Our final structure will be like Screen Shot 2014-03-11 at 9.18.28 PM You can remove bootstrap.js inside the lib folder if you want. We will be referring only the minified file. Open index.html and we will set up reference to all the required resources. Copy paste the below to index.html

Do notice the data-ng-app=”” on line no 2. This is how we tell Angular to get started. There are other ways of writing the same like

<html ng-app="">  or  <html ng-app>

Its up to you. The way I wrote kind of gives a feel of completeness, again you can write it any way & Angular will work the same way.

Next create another file in the root of the movieStub folder & name it index.js. This will be our sever. Open index.js & paste the below code

That’s it!! Our basic template is done.

Back to Terminal/Prompt, run node index.js. This should start the server. Now navigate to   http://localhost:2595/ in your favorite browser & you should see our app name as heading and a sub heading. You can copy this folder structure as is and save it as a template and can use this for other projects. Now, lets dig into some Angularjs concepts.

Model Bindings [code]

Angular uses html markup as templates, and lets you define dynamic values with placeholders using the double curly braces notation {{ }}.  Angular tries to resolve the value inside the double curly braces, using a scope variable ($scope). To understand this, open index.html & add below highlighted lines

Check if the node server is running ( node index.js ) & refresh our home page  http://localhost:2595. You should see something like model_bindingAnd now, enter a movie name

model_binding_value

And bam!! The value of your favorite movie appears as you type in. So, lets analyse what all is going on.

  • Line 2  – Tells Angular to begin the magic.
  • Line 14 – We define a value (movieName) for ng-model attribute. This value will act as a variable storing the text box value. As soon as Angular see a variable inside the ng-model attribute, it will bind the variable to the $scope object & monitors for changes.
  • Line 15 – We use the movieName variable here. When the value gets updated, Angular notifies the changes to all the {{movieName}} & updates them. Also note the ng-show attribute. This tell Angular to show line 15 only when there is a valid value for movieName. 

PS: ng-model & ng-show are called as Angular directives. More on that in a moment.

Two_Way_Data_Binding

Here our template is the h1 tag, when compiled becomes our view and model is movieName.

You can read more about data bindings here.

Repeaters [code]

Repeaters are “for loops” for all you programmers. We define a list in the Angular scope & then iterate the list using a ng-repeat directive & display the data.

What are these directives you ask?

At a high level, directives are markers on a DOM element (such as an attribute, element name, or CSS class) that tell AngularJS’s HTML compiler ($compile) to attach a specified behavior to that DOM element or even transform the DOM element and its children.

More on directives here.

Now, lets create a new folder named controller inside public/js. This is where our controllers reside. Next create a new file and name it app.js.

A controllers is a JavaScript constructor function that is used to augment the Angular Scope. Remember the $scope object? This will set up the initial state of the $scope object.

Before that we will create a module & hook up the controller to it.

You can think of a module as a container for the different parts of your app – controllers, services, filters, directives, etc.

Copy the following code to controller/app.js

We create a new controller named movieStubController and append an array of movies to the $scope object.

Now, in our index.html, we will add a ng-repeat directive to iterate over the movies array and print the object. Before we do that, we need to tell Angular that our app scope is defined here. For that we update our ng-app directive to the name of the module. And then add a new ng-controller directive to the body tag. The updated index.html would be

On line 19, we are printing the id of the current movie, name & rating. This should give you an idea of the flow. If you refresh  http://localhost:2595/ page, you should see something like

Screen Shot 2014-03-13 at 9.19.12 AM

Filters [code]

Lets say that, we need to show all the movie names in uppercase. But we are not allowed to change the data source. This can be achieved via Angular Filters. Filters will take the raw data from model and performs action on it like converting the data to uppercase or lowercase or actually “filter” the data. Lets take a look.

Open your index.html & update line no: 19 from  {{movie.id}} - {{movie.name}} - {{movie.rating}} to  {{movie.id}} - {{movie.name | uppercase}} - {{movie.rating}}.

Back to our webpage & refresh, you should see all the movie names are in uppercase. To add a filter, we append a pipe (|) symbol next to the object/array/string you are trying to modify followed by the filter name. In this case a uppercase.

Now, lets print the list in “reverse alphabetical” order. For that replace line 18 from <li data-ng-repeat="movie in movies"> to  <li data-ng-repeat="movie in movies | orderBy:'name':true">, refresh the page and Bam!!

Do notice this time we are running the filter on the complete movies array. You can read more about orderBy here.

Another important filter is the json. This is very helpful when you are debugging. If you want to see what is inside your object, you can use this filter. Add the following line of code after the ending tag of ul on line 21  <pre>{{ movies | json }}</pre>  and refresh the page. You should see something like

Screen Shot 2014-03-12 at 9.38.25 AMNow, you know what exactly you are dealing with.

Using filters, we will let the user search for a movie from the list. Update your index.html as below

We are adding a text box on line no 21, which will act as a input source. Refresh the page, your output will be

Screen Shot 2014-03-11 at 11.13.23 PMThe logic is very similar to what we have done in modal bindings. The search model from the textbox is passed as input to the filter on line 26.  Also do notice that on line 26, we have 2 filters going on.

More about filters here.

Scope Functions [code]

Now, lets say that a user wants to know how many tickets are available for each movie. For this requirement, we will add a clickable link to every movie. Next when a user clicks on it, we will check our movies object against the clicked movie & show the availability. So lets get cracking.

First app.js, we will create a new function, that will take a movie id & return the movie object. So, here is the code for that

And we update our index.html as follows

Things to notice. Line 29 has a ng-click directive, which will call our getMovieById function. The argument to the function is the movie id. On line 33, Once the current movie variable is updated, we will show the availability for the clicked movie.

Save, refresh the page. Now when you click on the availability link next to each movie, you will see the availability value at the bottom of the list.

With the concept of scoping, we are for sure not polluting the global name space, Ensuring clean maintainable code.

In this way, we bind a function to a scope object & as long as the scope lives, we can access the method. Also do note that if we spawn any new scopes inside this controller (which we will a bit later on), the current scope will be inherited.

Partial Views [code]

Angular provides a simple way of implementing partial views. Components like headers & footers can be stored as templates & easily included in the page.

Lets create a new folder inside the public folder and name it tmpl. Inside that, create another file and name it header.html. Cut the below 2 lines of header from index.html

and paste it inside the newly created header.html. Now in index.html, in place of the above 2 lines, add

See the value of src? This is the path to the header source template. We will define this value inside our controller – app.js. Add the following line inside our movieStubController() 

And then refresh the page. You should not see any change. The page should load the same way. If you view source, the mark up will not reflect the header tags & if you inspect element via Firebug or Developer tools, the injected markup will appear.

Routers [code]

Moving to the awesome parts of Angular, we will take a look at Routers. In this part, we will integrate the concepts we have learned so far.

Lets say that a user wants to see the complete details of the movie when he clicks on it, not below the list but in a new “View” altogether. We would leverage Angular’s Route Provider.

To work with routers, we need to include an Angular extra named angular-route.min.js. Navigate to Angularjs downloads & click on the download link. Bottom left hand corner of the popup, you will see a link named extras. Click on it. In the next page, look for angular-route.min.js. Download and save it to public/js/lib.

Next, we will create a new folder named router inside public/js folder & create a new file named router.js. Copy the below code to router.js

In this file, we have added our routes to which we will respond with a new view. If the URL is the root URL or home URL, we load the home.html partial If the route is /movie and a movie id, we redirect to movie.html (which, we will create now) & trigger the movieDetailsController. If we are not aware of the current URL, we will redirect to home route.

Next, Create a new file inside tmpl folder and call it home.html. We will abstract all the content from the index.html into this file, so that we can switch views easily. You will understand what I mean in a moment. Copy the below contents to home.html

Next create another file and name it as movie.html and add the below code

And your index.html should be updated to

Notice that we have added a new div on line 19. This is our place holder for all our pages. Depending on the page URL, Angular will fetch the corresponding view & fill this tag. We have added the reference to angular-route.min.js & router.js too.

Now finally, the updated controllers/app.js

Do note that we have added a new dependency to our module ngRoute. Next, we have also added 1 new function to the scope named back(), this is for navigating back to the previous view. And a new controller, that will populate the current movie object from the id in the URL.

All this will get cleared up in a moment. Save all the files and refresh our home page http://localhost:2595/. Do notice the url  http://localhost:2595/#/. Anything after the #/, Angular will look for in the routes we have configured. Your home page should be like

home-routeYou can click on review & you should be redirected to a new view, like

Screen Shot 2014-03-14 at 10.31.52 AM

Click on the back link and you should be taken to the movies list page. Play around for a while, have a look at the code again till you connect the ends of each layer. If you are still confused about something do drop a note.

Housekeeping [code]

Now we have a basic structure going on. I have cleaned up the UI to make it more of a movie site. First create a new file and name app.css inside public/css. And then update the following files

public/css/app.css

public/index.html

public/tmpl/header.html

public/tmpl/home.html

public/tmpl/movie.html

public/js/controller/app.js

Save all the files and refresh the page. You should see something like this

Screen Shot 2014-03-12 at 9.42.32 PM Screen Shot 2014-03-12 at 9.42.48 PMLooks a lot better doesn’t it?

Services [code]

Angular services are substitutable objects that are wired together using dependency injection (DI). You can use services to organize and share code across your app.

Angular services are:

  • Lazily instantiated – Angular only instantiates a service when an application component depends on it.
  • Singletons – Each component dependent on a service gets a reference to the single instance generated by the service factory.

As part of this tutorial, we will have a sample data file on the server. When we hit a certain end point, the server will dispatch this data as response.

We need to download another Angular extra named angular.resource.min.js. Navigate to Angularjs downloads & click on the download link. Bottom left hand corner of the popup, you will see a link named extras. Click on it. In the next page, look for angular.resource.min.jsDownload and save it to public/js/lib.

Next, lets create a new folder name data at the root (/movieStub). Inside this create a new file and name it movies.json. Copy & paste the below json object.

Next, we will update our server index.js, so that when we hit the end point /movies, it will dispatch this data. Update the index.js to

Create a new folder & name it service. Inside this, create a new file & name it services.js. We will define our factory here.

You can read more about Factory & Services here.

Update the services.js with the below code

Update index.html to refer the newly created js file by adding this line at the end of all script tags in the head   <script type="text/javascript" src="js/service/services.js"></script> &  <script type="text/javascript" src="js/lib/angular-resource.min.js"></script> after the angular-route.min.js file.

Update app.js as

Save all the files, stop the server & restart it by running node index.js (since we have updated our index.js) & you should see that the data loads up from the json file! And you page should look something like

Screen Shot 2014-03-14 at 11.14.53 AM

 

All the data is now coming from the server! And as you have seen, the process is pretty simple.

Posting Data – Book Tickets [code]

We have showed all the movies we are airing. Now lets provide the user an option to book tickets. For this, we will add a new partial view. Inside public/tmpl/ create a new file named bookTickets.html. Add the below contents

In this page, we are showing the summary of the movie the user clicked to book tickets for. The we give him an option to add the quantity and select the date.

Do notice the ng-disabled attribute on line 25, on the submit button. If the validation fails, we are disabling the submit button. And ng-pattern is a very powerful utility when dealing with inputs. We can write a regular expression in the pattern and  we can check the validation using formName.formField.$valid value. This will be false when the validation fails. Which we are leveraging to show an error message as well as disable the submit button.

Next, lets update the router.js with the new route. Updated public/router/router.js

Next, we will update our controller and add functionality for the post. Add the following code to controller/app.js

Do notice the onlyNumbers regular expression is defined here. Next, we are creating a placeholder object named formData. We will use this to map the values from form, so that we can send the data to the server as a single object.

Along with the tickets quantity & date, we need to store the movie id & movie name for display purposes.

We are creating a processForm() to send the data to server. This is very much similar to jQuery Ajax.

Next, we need a server side endpoint to update the booking details. Lets add that code to index.js. Copy the below code and replace the index.js code.

We have added the app.post().

Lets say that, a user is on the movie details page and s/he wants to book a ticket. For that lets add a book button to public/tmpl/movie.html. Updated movie.html.

And, lets enable the book button only when we have an availability. Lets update tmpl/home.html. Replace <a href="#" class="btn btn-success " role="button ">Book »</a>  to  <a data-ng-href="#/bookTickets/{{movie.id}}" class="btn btn-success " role="button" data-ng-disabled="movie.availability == 0">Book »</a>.

If you save the files and run the app, you can book tickets. Click on a Book button & you will be shown a new view to book tickets. Enter the quantity & date. Click on submit. Now open your console to see the response logged

Screen Shot 2014-03-14 at 8.34.01 PM

 

Simple right! Now lets build a view to show all the bookings.

Fetch Data – Show Booking Details [code]

For that, we will define a new route open router/router.js & update with the following

Next, we will add a service endpoint on the client side. This will be similar to the movies. But this will return the list of bookings made. Open service/services.js and add the below code

And a new controller to fetch the details

Do notice the isActive() & isActivePath() methods on line nos. 28 & 32. we will use them in a moment in the header to toggle menu active status.

Next, lets add the actual view bookings.html. Inside the tmpl folder create a new file named bookings.html & add the below code.

We will also update the header.html as below

Next, the heart of the logic. The server. Update the index.js with the below code

Save all the files, restart the server and Bam!! You should see a new tab named Bookings & if you book the tickets, it will redirect you to this page with the booking details.

Screen Shot 2014-03-14 at 8.51.18 PM

 

Thats it!! Our App is completed.

Hopefull this app will help you as a guideline to make more awesome SPA apps with Angularjs.


Thanks for reading! Do comment.

@arvindr21