Book Image

Angular 2 Cookbook

By : Patrick Gillespie, Matthew Frisbie
Book Image

Angular 2 Cookbook

By: Patrick Gillespie, Matthew Frisbie

Overview of this book

Angular 2 introduces an entirely new way to build applications. It wholly embraces all the newest concepts that are built into the next generation of browsers, and it cuts away all the fat and bloat from Angular 1. This book plunges directly into the heart of all the most important Angular 2 concepts for you to conquer. In addition to covering all the Angular 2 fundamentals, such as components, forms, and services, it demonstrates how the framework embraces a range of new web technologies such as ES6 and TypeScript syntax, Promises, Observables, and Web Workers, among many others. This book covers all the most complicated Angular concepts and at the same time introduces the best practices with which to wield these powerful tools. It also covers in detail all the concepts you'll need to get you building applications faster. Oft-neglected topics such as testing and performance optimization are widely covered as well. A developer that reads through all the content in this book will have a broad and deep understanding of all the major topics in the Angular 2 universe.
Table of Contents (18 chapters)
Angular 2 Cookbook
Credits
About the Author
About the Reviewer
www.PacktPub.com
Customer Feedback
Dedication
Preface

Migrating an application to component directives


In Angular 1, there are several built-in directives, including ngController and ngInclude, that developers tend to lean on when building applications. While not anti-patterns, using these features moves away from having a component-centric application.

All these directives are actually subsets of component functionality, and they can be entirely refactored out.

Note

The code, links, and a live example related to this recipe are available at http://ngcookbook.herokuapp.com/1008/.

Getting ready

Suppose your initial application is as follows:

[index.html] 
 
<div ng-app="articleApp"> 
  <ng-include src="'/press_header.html'"></ng-include> 
  <div ng-controller="articleCtrl as article"> 
    <h1>{{article.title}}</h1> 
    <p>Written by: {{article.author}}</p> 
  </div> 
  <script type="text/ng-template"  
          id="/press_header.html"> 
  <div ng-controller="headerCtrl as header"> 
    <strong> 
      Angular Chronicle - {{header.currentDate | date}} 
    </strong> 
   <hr /> 
  </div> 
  </script> 
</div> 
[app.js] 
 
angular.module('articleApp', []) 
.controller('articleCtrl', function() { 
  this.title = 'Food Fight Erupts During Diplomatic Luncheon'; 
  this.author = 'Jake'; 
}) 
.controller('headerCtrl', function() { 
   this.currentDate = new Date(); 
}); 

Note

Note that this example application contains a large number of very common Angular 1 patterns; you can see the ngController directives sprinkled throughout. Also, it uses an ngInclude directive to incorporate a header. Keep in mind that these directives are not inappropriate for a well-formed Angular 1 application. However, you can do better, and this involves refactoring to a component-driven design.

How to do it...

Component-driven patterns don't need to be frightening in appearance. In this example (and for essentially all Angular 1 applications), you can do a component refactor while leaving the existing template largely intact.

Begin with the ngInclude directive. Moving this to a component directive is simple—it becomes a directive with templateUrl set to the template path:

[index.html] 
 
<div ng-app="articleApp"> 
  <header></header> 
  <div ng-controller="articleCtrl as article"> 
    <h1>{{article.title}}</h1> 
    <p>Written by: {{article.author}}</p> 
  </div> 
  <script type="text/ng-template"  
          id="/press_header.html"> 
  <div ng-controller="headerCtrl as header"> 
   <strong> 
      Angular Chronicle - {{header.currentDate | date}} 
    </strong> 
   <hr /> 
  </div> 
  </script> 
</div> 
[app.js] 
 
angular.module('articleApp', []) 
.controller('articleCtrl', function() { 
  this.title = 'Food Fight Erupts During Diplomatic Luncheon'; 
  this.author = 'Jake'; 
}) 
.controller('headerCtrl', function() { 
   this.currentDate = new Date(); 
}) 
.directive('header', function() { 
   return { 
   templateUrl: '/press_header.html' 
 }; 
}); 

Next, you can also refactor ngController everywhere it appears. In this example, you find two extremely common appearances of ngController. The first is at the head of the press_header.html template, acting as the top-level controller for that template. Often, this results in needing a superfluous wrapper element just to house the ng-controller attribute. The second is ngController nested inside your primary application template, controlling some arbitrary portion of the DOM. Both of these can be refactored to component directives by reassigning ngController to a directive controller:

[index.html] 
 
<div ng-app="articleApp"> 
  <header></header> 
  <article></article> 
</div> 
[app.js] 
 
angular.module('articleApp', []) 
.directive('header', function() { 
  return { 
    controller: function() { 
      this.currentDate = new Date(); 
    }, 
    controllerAs: 'header', 
    template: ` 
      <strong> 
        Angular Chronicle - {{header.currentDate | date}} 
      </strong> 
      <hr /> 
    ` 
 }; 
}) 
.directive('article', function() { 
   return { 
   controller: function() { 
      this.title = 'Food Fight Erupts During Diplomatic Luncheon'; 
      this.author = 'Jake'; 
   }, 
    controllerAs: 'article', 
    template: `     
      <h1>{{article.title}}</h1> 
      <p>Written by: {{article.author}}</p> 
    ` 
 }; 
}); 

Tip

Note that templates here are included in the directive for visual congruity. For large applications, it is preferred that you use templateUrl and locate the template markup in its own file.

How it works...

Generally speaking, an application can be represented by a hierarchy of nested MVC components. ngInclude and ngController act as subsets of a component functionality, and so it makes sense that you are able to expand them into full component directives.

In the preceding example, the ultimate application structure is comprised of only components. Each component is delegated its own template, controller, and model (by virtue of the controller object itself). Sticklers will dispute whether or not Angular belongs to true MVC style, but in the context of component refactoring, this is irrelevant. Here, you have defined a structure that is completely modular, reusable, testable, abstractable, and easily maintainable. This is the style of Angular 2, and the value of this should be immediately apparent.

There's more...

An alert developer will notice that no attention is paid to scope inheritance. This is a difficult problem to approach, mostly because many of the patterns in Angular 1 are designed for a mishmash between a scope and controllerAs. Angular 2 is built around strict input and output between nested components; however, in Angular 1, scope is inherited by default, and nested directives, by default, have access to their encompassing controller objects.

Thus, to truly emulate an Angular 2 style, one must configure their application to explicitly pass data and methods to children, similar to the controllerAs encapsulation recipe. However, this does not preclude direct data access to ancestral component directive controllers; it merely wags a finger at it since it adds additional dependencies.

See also

  • Componentizing directives using controllerAs encapsulation shows you a superior method of organizing Angular 1 directives

  • Implementing a basic component in AngularJS 1.5 details how to write an Angular 1 component

  • Normalizing service types gives instruction on how to align your Angular 1 service types for Angular 2 compatibility