Prototyping our application

Many a times, while building large client-side applications, things get a lot clearer when we start with designing our layout and views and, in general, setting up the application click flow.

We will start by using bootstrap to get our basic grid in place.

Setting up our index.html file

Let’s open up our index.html file and add the Bootstrap CSS. For the sake of convenience, we will use the Simplex Bootswatch theme by adding its CDN link as follows:

<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootswatch/3.1.1/simplex/bootstrap.min.css"/>

Next, we will add the navigation bar just under the body tag or our index.html file, as shown in the following code:

    <nav class="navbar navbar-fixed navbar-inverse" role="navigation">
    <div class="container">
      <a class="navbar-brand" href="/">Garage Commerce</a>
        <ul class="nav navbar-nav">
    <li><a href="#/toys">Toys</a></li>
    <li><a href="#/books">Books</a></li>
  </ul>
  </nav>

Next, we will add the container-fluid class to our ui-view as follows:

<div class="container-fluid">
<div  ui-view></div>
</div>

Creating the controllers

Let’s open up the js/controllers.js file, and add the controller functions with some dummy scope data:

'use strict';
angular.module('myApp.controllers', []).controller('ProductsCtrl', ['$scope', '$stateParams',
        function($scope, $stateParams) {
            $scope.category = $stateParams.category
            $scope.productsListing = [{
                    product_id: '123',
                    title: ' Baby Rattles',
                    price: 2,
                    userName: 'John Doe'
                }, {
                    product_id: '456',
                    title: ' Kiddy Laptop',
                    price: 12,
                    userName: 'Sandy Peters'
                }

            ]

        }
    ])
    .controller('ProductDetailsCtrl', ['$scope', '$stateParams',function($scope, $stateParams) {
            $scope.id = $stateParams.id;
            $scope.product = {
                'title': 'Kiddy Laptop',
                'description': 'lorem lipsum do re me.',
                'price': 12,
                'userName': 'Sandy Peters'

            }

        }
    ]);

Essentially, what we are doing here is injecting the stateParams object and storing the category and ID values into scope objects.

We are also setting up the $products scope objects with dummy data.

Creating the product partials

With the controllers in place, let’s work on getting our partials ready.

Create a new file called products.html in the partials folder. This will be our product listing page. Let’s add the following code:

<h1>{{category}}</h1>
<hr/>
<!-- 1st Column -->
<div class="col-md-5">
   <div class="row-fluid listing sidebar" >
   <div class="listing" ng-repeat="product in productsListing">


   <h2><a ng-href="#/{{category%20+'/'+product.product_id}}">{{product.title}}</a> </h2>

   <h5>{{product.price |currency}}</h5>

   <p><i>-by:{{product.userName}}</i></p>
   </div>
   </div>


</div>
</div>

<!-- 2nd Column -->  
<div class="col-md-7">
   <div class="slide" ui-view></div>
</div>

We are splitting our product listing page layout into two columns. On the left column, we will be listing out our products, and on the right column, we will display the details of the selected product.

As you might have noticed, the right-hand column has a nested view within which we plan to show our product details. From a usability point of view, this kind of a layout would allow users to quickly browse through products, without having to toggle back and forth between the product listing and details page, as it would have been the case in traditional e-commerce sites.

Let’s create our product details page within the partials folder; we will call the page products.details.html. We use the dot notation to define the parent and child state views. In our case, the product is the parent to the details view.

It is important to follow the right dot notations and naming conventions to ensure that the UI-Router is able to properly load the nested views. Add the following code to the products.details.html page:

<p class="title">{{id}}</p>
<h1>{{product.title}}</h1>
<p>{{product.description}}</p>
<h3>{{product.price|currency}}</h3>

Save the files, refresh the app in the browser, and click on the category and product links to ensure that all the views are loading up properly.

Adding animations to the view transitions

The beauty of single-page apps is that they allow you to add interesting transition effects and animations. In this case, we would like our product details view to slide in from the right, each time a product is selected from the listing.

We will do this using the ngAnimate module. The first step is to include our angular-animate js library in the index.html file as follows:

  <script src="bower_components/angular-animate/angular-animate.js">
    </script>

Next, we include ngAnimate as a dependency for our app in the app.js file as follows:

angular.module('myApp', [
 ……….
  'ngAnimate'
])

Adding in the CSS transition effects

The ngAnimate module works in a slightly different way with the UI-Router as compared to ngRoute. In the case of ngRoute, the animation classes such as ng-enter, ng-leave, and ng-enter-active are automatically added.

In the case of the UI-Router, we need to define a CSS class called slide, and the ng-enter and ng-leave classes are linked to it. This is why we added the slide CSS class to the ui-view div on the second column of the product-listing partial.

Let’s now add the CSS transition effects in our app.css file as follows:

.slide {
    -webkit-transition: 0.5s ease-in-out all;
    transition: 0.5s ease-in-out all;
    position: relative;
}

.slide.ng-enter {
    position: absolute;
    left: 100% ;
}

.slide.ng-enter.ng-enter-active {
    left: 10%
}

What we are doing here is we are setting the transition time and easing effect on the main slide class.

Then, we create our ng-enter class, which is the starting position of the animation, and the ng-enter-active class, which is the ending position of our animation.

Save the file, and test the application on the browser. As you select a product, you’ll notice it entering the screen; however, you’ll also notice that due to the previous product staying in place, there is a bit of a jump in the animation. We need to gracefully fade out the previous product while the new product is entering in. We do this by adding the ng-leave and ng-leave-active CSS classes as follows:

.slide.ng-leave {
    opacity: 0.5
}

.slide.ng-leave.ng-leave-active {
    opacity: 0;
}

Test your application, and things should be looking good. This is how we are aiming for our final application to work