Understanding Two-way Data Binding in AngularJS

By Tanay Pant

In this tutorial I will demonstrate how two-way data binding works in AngularJS by building a dynamic business card generator. This generator will allow you to create your own virtual visiting cards, which you can personalize with your name, occupation, email, company logo, as well as links to both homepage and social media sites. You will be able to adjust both the background and text color of the card, using HTML5 color inputs and see any changes you make appear on the screen in real-time.

This is what we’ll end up with:

Angular Card Generator screenshot

Getting Started

We’re going to use Bower to manage our project’s dependencies. Bower is a package manager for the web and can be installed using npm (which means you’ll need to have Node.js installed). If you need help installing Node.js (or npm) then check out this recent SitePoint article on that very subject. If you need help installing Bower, then you can check out the instructions on their homepage.

Our dependencies for this project will be the Bootstrap Framework (for styling and an accordion component), Font Awesome (for icons), as well as jQuery (on which Bootstrap depends) and AngularJS.

Assuming you have Bower installed and configured, create a new directory, cd into that directory and use Bower to initialize the project:

mkdir ACG && cd ACG
bower init

Bower will then create a bower.json file in the root directory of your project. It will also ask you a few questions, such as the name of the project, name of the author, description and so on. Under name enter “ACG” ( for Angular Card Generator) and fill the rest out as you see fit (or just accept the default values). The resultant JSON file should look like this:

  name: 'ACG',
  version: '0.0.0',
  authors: [
    'Tanay Pant <>'
  description: 'Card Generator',
  keywords: [
  license: 'MIT',
  ignore: [

Next, run the following command in the terminal:

bower install bootstrap --save
bower install font-awesome --save
bower install angular --save

This will install all the required dependencies for our project in a directory called bower_components and save the dependencies to the JSON file. It is a good idea to add bower_components to .gitignore because you do not want to upload this folder to your GitHub repository, since any contributor can install the same dependencies by running bower install in the root of the project.

The Anatomy of an AngularJS App

In the ACG folder create a file index.html and another called style.css. Add the following code to index.html:

<html lang="en" ng-app="myApp" ng-controller="BusinessCardController">
    <title>{{ }} | Business Card</title>
    <meta charset="utf-8">
    <link href="path/to/bootstrap.min.css" rel="stylesheet">
    <link href="path/to/font-awesome.min.css" rel="stylesheet">
    <link href="style.css" rel="stylesheet">

    <script src="path/to/jquery.min.js"></script>
    <script src="path/to/js/bootstrap.min.js"></script>
    <script src="path/to/angular.min.js"></script>
      'use strict';

      angular.module('myApp', [])
      .controller('BusinessCardController', function($scope){
        $scope.user = {
          name: 'Tanay Pant'

We start the web page by adding both ng-app="myApp" and ng-controller="BusinessCardController" to the <html> tag. The ng-app directive is required to tell Angular that the whole page is an AngularJS application, while the ng-controller directive attaches a controller class to our view.

We then use the ng-bind directive in the title, so as to keep the title of the page in sync with our model, before including the relevant CSS files (in the <head>) and JS files (before the closing </body> tag). These files (apart from style.css) are all located in the bower_components folder.

Finally, we define myApp (our main module that’s loaded when the app bootstraps), as well as a BusinessCardController in which we will set up the initial state of the $scope object (the method by which our controller and view share data).

Accordions, Please!

Now we need a way to present the configuration options to the user. As we are using Bootstrap, we can make use of the collapse component—a basic accordion. The structure of an accordion panel is as follows:

<div class="panel panel-default">
   <div class="panel-heading">
     <h4 class="panel-title">
       <a data-toggle="collapse" data-parent="#accordion" href="#collapseOne">
         Panel Title
   <div id="collapseOne" class="panel-collapse collapse in">
     <div class="panel-body">
       Panel content

For each panel we want to replace the title with an appropriate icon and heading:

<i class="fa fa-user fa-fw"></i>Full Name

And the content with an input field:

Full Name: <input type="text" ng-model="" placeholder="Full Name" />

Note the ng-model directive. This binds the value of HTML control to the application data (in this case the name attribute of the user object we declared in the controller).

We can also give the panels a class of in to have them default to open.

This is what we’ve got so far. If you are following along at home, copy the HTML from the CodePen into index.html and the CSS from the CodePen into style.css.

See the Pen ZYqrKW by SitePoint (@SitePoint) on CodePen.

Wiring Things up

In the controller we can set some sensible defaults for our user object:

$scope.user = {
  name: 'Tanay Pant',
  designation: 'White Hat',
  email: '',
  link1: '',
  companylogo: '',
  color1: '#c0c0c0',
  color2: 'white',
  textcolor1: '#287cc2',
  textcolor2: '#666',

These values (which were bound to the input elements using ng-model, previously) can now be referenced inside of expressions—JavaScript-like code snippets that are usually placed inside curly braces. This means that if we write {{ }} anywhere within our ng-controller, it will evaluate to whatever is currently set to.

We can make use of this when creating our card. Creating a title that automatically updates according to whatever was entered into the “Full Name” input element, is as simple as:

<h1>{{ }}</h1>

Here’s a second iteration with everything working as expected (I’ve removed the second accordion due to space restrictions). You will need to update index.html and style.css with the HTML and CSS from the CodePen. The JavaScript goes inside our controller.

See the Pen Working Demo of Card Generator by SitePoint (@SitePoint) on CodePen.

<img ng-src="{{ user.companylogo }}" class="logo">
<a ng-href="mailto:{{ }}">{{ }}</a>

Please note that for the card’s logo, we are using a directive called ng-src. This is because if we just use src, the browser will start fetching the URL in raw format before AngularJS replaces the expression. We are also using ng-href for the same reason.

An important part of the code is the social links button. We have used the ng-if directive (which removes or recreates a portion of the DOM tree based on an {expression}) in both the Facebook and Google+ username columns, but not in the Twitter profile, as it is required. This means that the Facebook and Google+ icons will only be displayed if a user has entered their respective profile URLs.

<span class="facebook" 
      style="color:{{ user.textcolor1 }};" 
  <a ng-href="{{ user.fusername }}" 
     title="{{ }} on Facebook" >
    <i class="fa fa-facebook fa-fw"></i>

Now we consider the case where the user neither has a Facebook nor a Google+ profile. That will mess up our design, since it leaves a big empty space in front of the twitter icon. We can solve this problem by using the ng-show directive on the span tag. This displays the user’s full Twitter handle only if the Facebook and Google+ URLs are not set. Pretty easy, huh?

<span class="twitter" style="color:{{ user.textcolor1 }};">
  <a ng-href="{{ user.tusername }}" 
     title="@{{ user.tusername }}">
    <i class="fa fa-twitter fa-fw"></i>
  <span class="twitter-handle" 
        ng-show="!user.fusername && !user.gusername">


I hope that the Card Generator helped you in learning the basic concepts of data binding in AngularJS. You can find a complete demo of the code on CodePen, or you can clone the code for this article from GitHub. I encourage you to fork the repository, play around with the code and see what cool things you can come up with.


Hi, thanks for the simplicity ! Good tutorial.
I got a question can we get binding directly through a css file ?


Thanks, Houssem! I'm afraid at the moment that is not possible, however in your controller, you can write:

$scope.mystyles = {
 .myclass: {
  display: block

In the HTML file:


@Tanay. This is a complete tutorial, from environment set up to execution.


What's your opinion on AngularJS 2.0? By all means, I'm no expert in AngularJS but I've heard there was a civil war going in the community.


Well, AngularJS is good for making web applications, however if I were working on a mobile application, Vue.js or React.js would be the libraries of my choice since Angular is a bit heavy, in my opinion. But yes, AngularJS does make life easy smile


I'm not sure if you responded my question but I've heard many that abandon AngularJS due to 2.0 being dramatically different and not being backward compatible. Some even worry that 2.0 may kill AngularJS community.


Well, I agree with what you have heard, but AngularJS is still widely used by big projects. Empires rise and fall all the time wink But I for one believe that would not be the case with Angular.


Yeah... Angular had such a popularity. One developer left Google's Angular Team and started his own framework


Interesting Article.


@sg707 there will be a couple of articles on the Aurelia framework coming to the JS channel in the next couple of weeks. I think Aurelia could become a real contender on the framework scene.

As regards what happened with Angular 2.0 - it will be a complete rewrite of the framework. There is currently no upgrade path from 1.x and as you can imagine, that caused quite a furore. You can read all about that here:


Never heard of that one but I'm not surprised that others will take advantage of this opportunity. If Aurelia ever gets a 'In Action' book from manning then I'd definitely check it out.

Since there is no upgrade path, I believe Angular community will lose trust on next major iteration.. Who's to say that it's not backward compatible or no upgrade path? As a technical enthusiasts, I wouldn't care that much as long as it's fun to use it. From business perspective... it looks pretty horrible ROI. I think it would be hard to convince to use Angular 2 to upper management...


The one thing that Angular has going for it is that it is backed by Google.
This table with a few metrics on community comparing Angular, Ember and backbone makes quite interesting reading.


I'm not so sure... I'll wait and see. Who's to say that Angular 3.0 will be the same.. no upgrade path. Other frameworks are easily replaced but MVC frameworks are kind of like heart transplant. I suppose using AngularJS 2.0 is ok for now..assuming they'll supported for at least 3~5 years or so. I hope I'm wrong but I feel AngularJS is heading downhill. I am NOT saying AngularJS 2 is not a good framework. Just saying that there is a chance that Application built with AngularJS 2 may not have upgrade path to AngularJS 3. From business perspective, this is a very bad ROI.



Because We Like You
Free Ebooks!

Grab SitePoint's top 10 web dev and design ebooks, completely free!

Get the latest in JavaScript, once a week, for free.