March 11, 2015

Directives and Views in AngularJS

Directives and Views in AngularJS

AngularJS views mix data from the model into an HTML template. You use AngularJS directives to tell AnguluarJS how to mix the data into the HTML template.

Here i am going to take an example to show you how this works. I am going to fetch the user details and their repo details respectively from the github api and sort them. I am also going to create a search box to search the user and display their details.

ng-model

What i am going to do is have an input where i can type in any username that i want, click a button, then it will go out and fetch the information for me. Instead of hardcoding that value i want to be able to input the value as a user.

<form name="SearchUser">
   <input type="search" placeholder="Find user" ng-model="username">
   <input type="submit" value="Find">
</form>

What ng-model will do is as the user types into the input, ng-model will push the value of the input into my scope object. ng-model is an extremely useful directive because you can apply to input, select, textarea. What ng-model will do is always keep your data in synch. It's going to move information that the user types into your model.

ng-click

Now i want to know when the user is ready to search for a particular username and there are couple of ways to do that. One way to do is attach a directive ng-click to the input button. Typically the expression is going to be a function call.

   <input type="submit" value="Find" ng-click="search()">

When someone clicks on the button angular goes out and finds that function that is defined in my model. It is attached to $scope and i want angular to invoke it. In this case it's a search function. Inside the search function i am going to write the code that gets the username, calls the github API and retrieves the information of that particular user.

When you write expressions for ng-click some of them can be rather fancy, you can even incude thigs like parameters to that method call. In this case i am going to call search and pass the parameter username. This is not necessary as scope will already have username as a property. Thanks to ng-model. But i am going to leave that parameter there just to see how easy it is to call search and pass something along.

<input type="search" placeholder="Find user" ng-model="username">
<input type="submit" value="Find" ng-click="search(username)">

$scope.search = function(username) {
   $http.get('https://api.github.com/users' + username)
        .then(onUserComplete, onError);
};

When the input is empty, nothing happens. It would be nice to tell the user that something needs to be typed. Easy way to do this is to add html validation attribute required to the input field.

<input type="search" placeholder="Find user" ng-model="username" required>

ng-submit

In order to tell the browser to be able to tell the user, that this particular input is required, i wont be able to handle ng-click on this button event. Instead i will handle this in the form using the directive ng-submit. Use this directive to catch the submit event of the form and have that call search passing in the username

<form name="SearchUser" ng-submit="search(username)">
   <input type="search" placeholder="Find user" ng-model="username">
   <input type="submit" value="Find">
</form>

ng-repeat

The information we get from github includes repos_url. We are going to get some information's from the github like name of the repo, number of stars obtained for that repo and the language and view this in html.

var onUserComplete = function(response) {
   $scope.user = response.data;
   $http.get($scope.user.repos_url)
 .then(onRepos, onError);
};

var onRepos = function(response) {
   $scope.repos = response.data;
};

Now we have display information's about each repository into html. Typically we will display information from an array inside of an unordered list or a table. I am going to go with table because i want to display multiple things about each repository.

I need a table row where i am going to display each repository. I am going to use the directive ng-repeat. Here i will write an expression like ng-repeat="repo in repos". The idea is like that ng-repeat is more likely a for loop.

<table>
   <thead>
      <tr>
         <th>Name</th>
         <th>Stars</th>
         <th>Language</th>
      </tr>
   </thead>
   <tbody>
      <tr ng-repeat="repo in repos">
         <td>{{repo.name}}</td>
         <td>{{repo.stargazers_count}}</td>
         <td>{{repo.language}}</td>
      </tr>
   </tbody>
</table>

This isn't very readable because it does not include any commas to the stars. The quick way to fix that is

{{repo.stargazers_count | number}}

Filters

Filters in angular allow you to format data for presentation. here i am going to sort by the repo having most stars. In order to that i will try orderBy filter.

g-repeat="repo in repos | orderBy: '-stargazers_count'"

Now let me do something intresting. Let us see the data by sorting order of name, star count or language.

$scope.repoSortOrder = "-stargazers_count";

<select ng-model="repoSortOrder" class="form-control">
    <option value="+name">Name</option>
    <option value="-stargazers_count">Star</option>
    <option value="+language">Language</option>
</select>

ng-show & ng-hide

We can hide or show pieces of our markup very easily. The directives ng-show & ng-hide both useful directives when you want to make things appear and disappear from the screen based on some expression and some flag that is in the model.

<div class="text-center" ng-show="user">
   <div><h2>{{user.name}}</h2></div>
   <div><img ng-src="{{user.avatar_url}}" title="{{user.name}}" /></div>
</div>

ng-include

Directive ng-include is useful for number of scenarios. ng-include can bring html from another source like another file and you can use that html in the current view. This is useful because you can break up complex page into pieces and is also useful if you have markup that you can reuse in other views of the application. For example the values that we are displaying like name, gravatars, repository details all can be added in a separate html file and include this in the current html using the directive ng-include.

<div ng-include="'userdetails.html'"></div>

Conclusion:

All together i am going to show you an example. I am going to use API from github to get the user information and display it in html. The user has an option to search the user he wanted to see. In addition i am going to get the github API for repository and fetch details from it. Let's even sort the data's as user wanted and display it in html.

HTML

<body ng-app="UserDetails">
   <div ng-controller="MainController">
      <h1 class="text-center">{{message}}</h1>

      <div class="error">{{error}}</div>

      <form name="SearchUser" ng-submit="search(username)">
         <input type="search" ng-model="username" class="form-control" required />
  <button class="btn btn-default">Find</button>    
      </form>

      <div ng-show="user">
         <h2>{{user.name}}</h2>
         <img ng-src="{{user.avatar_url}}" title="{{user.name}}" width="200px" />

         Order by:
         <select ng-model="repoSortOrder" class="form-control">
            <option value="+name">Name</option>
     <option value="-stargazers_count">Star</option>
     <option value="+language">Language</option>
  </select>
      </div>

      <table class="table" ng-show="user">
         <thead>
            <tr>
               <th>Name</th>
               <th>Stars</th>
               <th>Language</th>
            </tr>
         </thead>
         <tbody>
            <tr ng-repeat="repo in repos | orderBy: repoSortOrder">
               <td>{{repo.name}}</td>
               <td>{{repo.stargazers_count | number}}</td>
               <td>{{repo.language}}</td>
            </tr>
         </tbody>
      </table>
   </div>
</body>

JavaScript

(function() {
    var app = angular.module("UserDetails", []);

    var MainController = function($scope, $http) {

        var onUserComplete = function(response) {
            $scope.user = response.data;
            $http.get($scope.user.repos_url)
                .then(onRepos, onError);
        };

        var onRepos = function(response) {
            $scope.repos = response.data;
        };

        var onError = function(reason) {
            $scope.error = "Could not fetch the user data!";
        };

        $scope.search = function(username) {

            $http.get('https://api.github.com/users/' + username)
                .then(onUserComplete, onError);

        };

        $scope.username = "angular";
        $scope.message = "Github Users";
        $scope.repoSortOrder = "-stargazers_count";

    };

    app.controller("MainController", ["$scope", "$http", MainController]);
}());

Attachments:

We have to use this attachment to make AngularJS work.

<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.5/angular.min.js"></script>

Note:

I did not apply any style to the code. you can apply your own style.

demo

No comments:

Post a Comment

Popular Posts

Views