Creation of Components in Angular 1.5

With Angular 1.5 we can divide our application into components, making use of the .component () method. Before we could do it by using directives but this way the code is better adapted and prepares us for the jump to Angular 2.

The fundamental difference between directives and components is that, while directives receive a function, just like controllers or factories, the components receive an object. It really is similar in the sense that the directives at the end should return an object and the components directly serve that object to the component () method.

But in practice the components also allow us to extend the HTML in another way, creating new complete tags that we can incorporate and that hide within their own complexities, allowing a greater reuse and keeping its complexity encapsulated.

Creation of a Basic Component (Movie List Component)

Let’s create a component that displays a list of movies using the ng-repeat directive.

1. Component Declaration


(function () {
    "use strict";

    //Function to fetch the data from a json file
    function fetchMovies($http) {
        return $http.get("/movies.json").then(function(response) {
            return response.data;
        });
    }

    //Controller of the component
    function controller($http) {

        var model = this;
        model.movies = [];

        //This is a built-in angular event that is triggered when the controller of the component is instantiate
        //typically we put here the calls to the api to fetch data
        model.$onInit = function() {
            fetchMovies($http).then(function(movies) {
                model.movies = movies;
            });
        };

//Controller of the component
    function controller($http) {

        var model = this;
        model.movies = [];

        //This is a built-in angular event that is triggered when the controller of the component is instantiate
        //typically we put here the calls to the api to fetch data
        model.$onInit = function() {
            fetchMovies($http).then(function(movies) {
                model.movies = movies;
            });
        };

    }

    //Component Declaration
    angular.module("demoApp").component("movieList", {
        templateUrl: "scripts/app/templates/movieListComponent.html",
        controllerAs: "model",
        controller: ["$http",controller]
    });

}());

There are some key point to notice of the code above, Let’s start from the Component Declaration block and then we will go up on the code

  • We use the new method called “component” to register components into the modules. The name of the component that we pass to the component function must be written in “camel case”, if it is composed of several words. But then we will see that in the HTML we refer to the component separating the words by hyphens.
  • In component controllers we can assign names to define how the controller should be known within the component’s HTML, using the “controllerAs”. If we don’t specify any name by default the value will be $ctrl
  • In the controller attribute of the component we specify the function that will be the controller, in this case we create a separate function called controller and we are injecting to it the $http service. We use this $http service make a API call and get data from the server.
  • In the Controller function we can find method called $onInit. This is a lifecycle hook of the component, AngularJs components expose some built-in methods that are called at certain points in the life of the component. The most useful ones are the followings:
    • $onInit(): Called on each controller after all the controllers on an element have been constructed and had their bindings initialized. This is a good place to put initialization code for your controller.
    • $onChanges(changesObj) – Called whenever one-way bindings are updated. The changesObj is a hash whose keys are the names of the bound properties that have changed, and the values are an object of the form.
    • $onDestroy() – Called on a controller when its containing scope is destroyed. Use this hook for releasing external resources, watches and event handlers.
  • The rest of the code is just fetch the data from the server to show the list of objects in the view

2. Component HTML Template

'
<div>
<table class="table" style="width: 50%">
<tr>
<th>Title</th>
<th>Length</th>
<th></th>
</tr>
<tr ng-repeat="movie in model.movies">
<td>{{movie.title}}</td>
<td>{{movie.length}}</td>
</tr>
</table>
</div>
'

3.Use of the Component (index.html)

'
<html ng-app="demoApp">

<head>
    					<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" />
    <title>Angular Component Demo</title>
</head>
<body>
<div>
        <movie-list></movie-list></div>
<script src="scripts/angular.js"></script>
    <script src="scripts/app/module.js"></script>
    <script src="scripts/app/movieListComponent.js"></script>
</body>
</html>
'

Due to the name of the component is composed of several words (movieList), we must refer to the component separating the words by hyphens.

4. Result

Creation_of_Components_in_Angular_Result

Component architecture

Each component is responsible for doing a part of the application work, but they must relate and communicate with each other. Under the component architecture we have an element tree. They form a structure where some components include others, where each of them encapsulates an HTML and some application logic.

The key is that each component has its own unique scope. A component only knows the data that its controller handles, not being able to access the scope of other components, whether parents or children. This structure facilitates the development of applications, because one can know a priori where is the code that affects each part of the application.

For independent components to collaborate with each other, so that we get an application among all, it is necessary to exchange data. This is done through binding mechanisms and can be produced at various levels.

Binding between components

In the component architecture the data is passed through properties in the HTML and for it to work the declaration of the shared data in the JS has to be made. HTML properties work as component modifiers, sending data that can affect the component in a variety of ways.

Binding between components can be of several types. We can have binding to two ways, something typical of Angular, where the data travel from one component to the other and from the second to the first. But now in Angular 1.5 we can also create binding in a single direction, as well as sending raw data, which once delivered are not binned in one way or another.

In the bindings statement, each type of binding is defined by means of a symbol, the main ones are:

  • “=”: This serves to deliver a reference to an object. So whatever is being delivered is shared between components.
  • “@”: This is used to deliver a value. There is no binding of any kind.
  • “<“: This is used for one way binding The father transfers the child a value, but even if the child changes the new value does not travel to the father. However, if the father changes it, it does change in the child.Note: But, with the alternative “1 way binding”, if you transfer an object or an array, passing the reference in practice will still produce a traditional 2 way binding of Angular.
  • “&”: This last alternative allows you to send a pointer to a function

Creation of a Component using bindings and transclusion. (Movie Rating Component)

We will create a component that will allow us to set some rating to each movie in the list, we will have to buttons to add or reduce rating to the movies and the rating will be represented by starts. Let’s go through the code

1. Component Declaration

 	(function () {
	    "use strict";

	    var module = angular.module("demoApp");

	    module.component("movieRating", {
	        templateUrl: "scripts/app/templates/movieRatingComponent.html",
	        bindings: { //here we specify which properties we want to binding
	            value: "<" //that symbol means that that property will be set from the outside as an attribute in the component
	        },
	        transclude: true, //this means that content (html tags) can be put inside our component and we will display that html in the component
	        controllerAs: "model",
	        controller: function () {
	            var model = this;

	            model.$onInit = function () {
	                model.entries = new Array(model.value);
	            };

	            //this is a built-in angular event that is triggered when any change on the bindings properties is made
	            model.$onChanges = function () {
	                model.entries = new Array(model.value);
	            };
	        }

	    });

	}());

The idea in this component is receive a value(rating) from the outside of the component and base on that value create an array with the length of the value and then go through the array and for each position show a start, this way we represents the rating of the movie. The key points to notice in the code above are the following:

  • The attribute “bindings” on the component object contains another object which has all the properties that we want to binding, in this case we declared the property called “value” and we use the symbol < which means that property will be set from the outside as an attribute in the component.
  • The attribute transclude allow us to use transclusion the same way we use this functionality on the directives.
  • The method $onChanges is a lifecycle hook in the component that will be execute when angular detect any change on the properties that we are bindings, in this case the “value” property.

2. Component Html Template

'
	<span ng-repeat="entry in model.entries track by $index">
	    <!--The content put inside the component tag will be displayed inside the transclude tag, 	    if there is not content the * symbol will be displayed-->
	    <ng-transclude>

	        *
	    </ng-transclude>
	</span>
'

3. Use of the Component (this html belong to the Movie List Component)

'
<div>
<table class="table" style="width: 50%">
<tr>
<th>Title</th>
<th>Length</th>
<th>Rating</th>
<th></th>
</tr>
<tr ng-repeat="movie in model.movies">
<td>{{movie.title}}</td>
<td>{{movie.length}}</td>
<td>
                <movie-rating value="movie.rating">
                    <span class="glyphicon glyphicon-star"></span> <!--HTML THAT WILL BE TRANSCLUDE-->
                </movie-rating></td>
<td>
<div class="btn-group">
                    <button class="btn btn-default" ng-click="model.upRating(movie)">
                        <span class="glyphicon glyphicon-plus"></span>
                    </button>
                    <button class="btn btn-default" ng-click="model.downRating(movie)">
                        <span class="glyphicon glyphicon-minus"></span>
                    </button></div></td>
</tr>
</table>
</div>
'

We use the movie rating component on the movie list template, so the movie list component is the father of the movie rating component. The movie list component will set the value of the rating to the movie rating component.

4. Movie List Component Code

(function () {
    "use strict";

    var module = angular.module("demoApp");

    function fetchMovies($http) {
        return $http.get("/movies.json").then(function (response) {
            return response.data;
        });
    }

    function controller($http) {

        var model = this;
        model.movies = [];

        model.$onInit = function () {
            fetchMovies($http).then(function (movies) {
                model.movies = movies;
            });
        };

        model.upRating = function (movie) {
            if (movie.rating < 5) {                 movie.rating += 1;             }         };         model.downRating = function (movie) {             if (movie.rating > 1) {
                movie.rating -= 1;
            }
        };
    }

    //Component Declaration
    module.component("movieList", {
        templateUrl: "scripts/app/templates/movieListComponent.html",
        controllerAs: "model",
        controller: ["$http", controller]

    });
}());

5. Result

Creation_of_Components_in_Angular_Result2

In a next article I will explain how the routing of components works. Thanks for reading.

 

 

Advertisements
This entry was posted in AngularJs and tagged , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s