MEAN Tutorial (Part 4) : Build Front-end in AngularJs

July 10, 2015
by Inaam Hussain

This is the final part of the MEAN series. Here we will design Front-end of our application using AngularJS. We have already learned how to setup mongodb (see here) to store data and created web apis using node js and express 4 (see here).

DEMO DOWNLOAD

See below folder structure for Book app.

 

Folder Structure

Mongo book folder structure

Mongo book folder structure

Main App view

Now we will further see how to build an app using angular js. So let’s start with an over all full page UI architecture see below image,

MEAN Angular App

MEAN Angular App

List of things covered in app

In above image you can see we have covered following functionality for book app.

  1. List of all books with it’s details.
  2. Add new book data.
  3. Edit existing book data.
  4. Delete existing book data.
  5. Search for required books.
  6. Pagination For ‘n’ numbers of books.
  7. Loading Bar on the top.

 
Note : Before running this app make sure you have setup and started node server (see here) & MongoDB (See here).
 

Initial module & Route

First will initialize module.

app/app.js
var app = angular.module('bookapp', ['ui.router','angular-loading-bar','angularUtils.directives.dirPagination']);

In module you can see that we have define module name (i.e : bookapp). and then followed by angular libraries which is used in app (i.e: angular loading bar, UI router, pagination).
Now will make routes for add , edit & home page templates.

app/app.js
app.config(['$stateProvider','$urlRouterProvider',
    function ($stateProvider,$urlRouterProvider) {
        $urlRouterProvider.otherwise('/home');
        $stateProvider
            .state('home', {
                url: "/home",
                templateUrl: "templates/home.html"
            })
            .state('Newbook', {
                url: "/addnew",
                templateUrl: "templates/newbook.html"
            })
            .state('Editbook', {
                url: "/editbook",
                templateUrl: "templates/editbook.html"
            })
    }
]);

In above code config we have used UI router for loading templates based on action from UI. UI-router is a powerful third party library for routing in Angular applications.Using UI router we can easily change templates and pages, without reloading whole page.
First we need to define state name using .state('state Name', {'url':'Url which shown', 'templatesUrl':'template path'}).
Next in view side we need to add ui-view so that all templates load in that view div. See below code,

index.html
<div role="main" class="container theme-showcase">
    <div class="" style="margin-top:90px;">
        <div ui-view></div>
    </div>
</div>

For more information about UI-Router : visit Here

 

List of all books with itโ€™s details

First we will see html part how data should be displayed in table.

templates/home.html
<table class="table">
    <thead>
        <tr>
            <th>Book Name</th>
            <th>Book Author</th>
            <th>Price</th>
            <th>Edit</th>
            <th>Delete</th>
        </tr>
    </thead>
    <tbody>
        <tr dir-paginate="item in booklist | searchFor:searchBook | itemsPerPage: pageSize" current-page="currentPage">
            <td>{{item.bookname}}</td>
            <td>{{item.authorname}}</td>
            <td>${{item.price|number:2}}</td>
            <td><button type="button" class="btn btn-primary" ng-click="editBook($index)">Edit</button></td>
            <td><button type="button" class="btn btn-danger" ng-click="deleteBook($index)">Delete</button></td>
        </tr>
    </tbody>
</table>

and controller for that is,

app/app.js
app.controller('book-list',function($scope,$state,$http,sharedbook,$filter){
    $scope.booklist = {};
    $scope.pageSize = 5;
    $scope.currentPage = 1;
    $http.get("http://localhost:8080/book").success(function(response){
        if(response.error === 0){
            $scope.booklist = response.Books;
            $scope.items2 = $scope.booklist;
            $scope.$watch('searchBook', function(val){
                $scope.booklist = $filter('searchFor')($scope.items2, val);
            });
        }else{
            $scope.booklist = [];
        }
    });
   
    $scope.editBook = function($index){
        $scope.number = ($scope.pageSize * ($scope.currentPage - 1)) + $index;
        sharedbook.setProperty($scope.booklist[$scope.number]);
        $state.go('Editbook');
    };
   
});

We have created controller for showing book list that is book-list in which we are calling GET api to fetch all the book data which is stored in database. We assigned the data to $scope.booklist and that will interact with UI side in table.
 

Add new book data

For adding new book data we have created separate template in which you can see controller name add-new-book with three text field for book name, author name & Price so by click on submit button it will call addBook() function.
 

templates/newbook.html
<h2>Add new book</h2><hr>
<div class="row">
    <div class="col-md-6">
        <div class="well well-sm">
            <form ng-controller="add-new-book">
                <div class="form-group">
                    <label for="exampleInputEmail1">Book Name</label>
                    <input type="text" class="form-control" ng-model="bookdata.bookname" placeholder="Enter Book Name" required>
                </div>
                <div class="form-group">
                    <label for="exampleInputPassword1">Author Name</label>
                    <input type="text" class="form-control" ng-model="bookdata.authorname" placeholder="Enter Author Name" required>
                </div>
                <div class="form-group">
                    <label for="exampleInputPassword1">Price</label>
                    <div class="input-group">
                    <div class="input-group-addon">$</div>
                    <input type="text" class="form-control" ng-model="bookdata.price" placeholder="Amount" required>
                    </div>
                </div>
                <button type="submit" class="btn btn-success" ng-click="addBook()">Add Book</button>
            </form>
        </div>
    </div>
</div>
app/app.js
app.controller('add-new-book',function($scope,$http,$state){
    $scope.bookdata = {};
    $scope.addBook = function(){
        var payload = {
            "bookname":$scope.bookdata.bookname,
            "authorname":$scope.bookdata.authorname,
            "price":$scope.bookdata.price
        }
        $http.post("http://localhost:8080/book",payload).success(function(res){
            if(res.error == 0){
                $state.go("home");
            }else{
               
            }
        });
    };
});

So by calling addbook() function, we first fetch all required data and place the data in one payload object, which is passed while calling POST Api. Refer the code above.
 

Edit existing book data

For changing existing book data we have created a separate template in which you can see controller name edit-book with three text field for book name, author name & Price so by click on submit button it will call updateBook() function and on cancel button cancel() Function. see below code.

templates/editbook.html
<h2>Edit book Data</h2><hr>
<div class="row">
    <div class="col-md-6">
        <div class="well well-sm">
            <form ng-controller="edit-book">
                <div class="form-group">
                    <label for="exampleInputEmail1">Book Name</label>
                    <input type="text" class="form-control" ng-model="bookdata.bookname" placeholder="Enter Book Name" required>
                </div>
                <div class="form-group">
                    <label for="exampleInputPassword1">Author Name</label>
                    <input type="text" class="form-control" ng-model="bookdata.authorname" placeholder="Enter Author Name" required>
                </div>
                <div class="form-group">
                    <label for="exampleInputPassword1">Price</label>
                    <div class="input-group">
                    <div class="input-group-addon">$</div>
                    <input type="text" class="form-control" ng-model="bookdata.price" placeholder="Amount" required>
                    </div>
                </div>
                <button type="submit" class="btn btn-default" ng-click="cancel()">Cancel</button>
                <button type="submit" class="btn btn-success" ng-click="updateBook()">Update Book</button>
            </form>
        </div>
    </div>
</div>
app/app.js
app.controller('edit-book',function($scope,$http,$state,sharedbook){
    $scope.bookdata = sharedbook.getProperty();
    $scope.updateBook = function(){
        var payload = {
            "id":$scope.bookdata._id,
            "bookname":$scope.bookdata.bookname,
            "authorname":$scope.bookdata.authorname,
            "price":$scope.bookdata.price
        }
        $http.put("http://localhost:8080/book",payload).success(function(res){
            if(res.error == 0){
                $state.go("home");
            }else{
               
            }
        });
    };
    $scope.cancel = function(){
        $state.go("home");
    };
});

So by calling updatebook() function, first we will fetch all required data and place the data in one payload object which is passed while calling PUT Api by passing that payload and on cancel function will redirect it to home page. See above code for better understand.
 

Delete existing book data

Below is the delete book function deletebook function which you can see in table, it will call DELETE Api in which we are passing bookname which we need to delete. See below code

app/app.js
$scope.deleteBook = function($index){
    $scope.number = ($scope.pageSize * ($scope.currentPage - 1)) + $index;
    $http.delete("http://localhost:8080/book/"+$scope.booklist[$scope.number].bookname).success(function(res){
        if(res.error == 0){
            $state.go($state.current, {}, {reload: true});
        }else{
           
        }
    });
};

 

Search for required books

Here we have created filter for search. In table we have defined searchFor:searchBook in tr element. Based on that it will pass data to below filter function and then it will filter data based on book name and author name, and create one array name result[] then return that array to table with filtered data.

app/app.js
app.filter('searchFor', function(){
    return function(arr, searchBook){
        if(!searchBook){
            return arr;
        }
        var result = [];
        searchBook = searchBook.toLowerCase();
        angular.forEach(arr, function(item){
            if(item.bookname.toLowerCase().indexOf(searchBook) !== -1 || item.authorname.toLowerCase().indexOf(searchBook) !== -1){
            result.push(item);
        }
        });
        return result;
    };
});

 

Pagination For โ€˜nโ€™ numbers of books

For this we have angular library Dirpaginate directive.
In which we have to defined in module 'angularUtils.directives.dirPagination'.
and below code need to add in html file where you want to show pagination.

templates/home.html
<dir-pagination-controls boundary-links="true"  template-url="templates/dirPagination.html"></dir-pagination-controls>

In table dir-paginate with array of data.

templates/home.html
<tr dir-paginate="item in booklist | searchFor:searchBook | itemsPerPage: pageSize" current-page="currentPage">

We have a tutorial on search sort and pagination which you can have a look at for a detailed explanation.

 

Loading Bar on top

For this also we have you another library name Angular loading bar which is mostly used in one page app for showing that data is still loading.
For adding this library to your project we need to add 'angular-loading-bar' while defining module.

For more detail you can checkout this cool angular library for loading bar – Here

 

Conclusion

This was the last chapter in building an app with MEAN series, I hope you found this tutorial useful and by now you should be able to kick-off your development with MEAN.

About

Engineer. Blogger. I like to be updated on new upcoming emerging technologies.

Free PDF

Subscribe and get AngularJS Tips PDF. We never spam!
First Name:
Email:

9 comments

  1. Shakhrat
    |

    how to run this app on linux?

    • |

      Hi Shakhrat,

      You need to follow the parts of tutorials of MEAN Stack. in downloaded code you will find two folder in which Main app folder contains angular app & api folder contain node api’s.
      basically first will setup our mongodb then Rest Api’s and lastly Main angular app.
      You can read all the tutorials of this series or else watch Demo video, that will definitely help you to run this app.

      Thanks.

      • Shakhrat
        |

        I followed the instructions, but in the demo you run the application using xampp on windows. In ubuntu, i run the server using [node server.js], and it’s run the server. But how to run the application?

        • |

          You can directly run that application. and [node server.js] is for node API’s.
          All the api’s are created in nodejs. so if node server is running means you can access those api’s in front-end.
          Just go to app folder. and run index.html. i think it should work.

        • |

          Yes if you don’t want to run the Application on local-server you can navigate to the AngularApp folder and open index.html in browser, but make sure node server is running as it would be required to run APIs.

  2. |

    Can you tell me why dont using “app.use(express.static(path.resolve(__dirname, ‘angularApp’)));” in server.js file to open the localhost:8080?

    I believe its required to put server.js is “var path = require(‘path’);

    I could not figure it out… please help me thanks.

    • |

      Hi,
      In current scenario our web app and api’s is running independently. If you want to run with in node server then you have to link your webapp folder to base directly. like see below code,

      app.use(‘/’,express.static(__dirname+’/client’));

      in client folder we have to add our web app code. and start node server then you should be able to access UI.
      Thanks.

      • |

        This is very helpful and I want to said thank you so much for your hard worker and I learned alot! ๐Ÿ™‚ keep up i m looking forward more blogs from you.

Leave a Comment