Search icon CANCEL
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Conferences
Free Learning
Arrow right icon
Arrow up icon
GO TO TOP
Angular 2 Cookbook

You're reading from   Angular 2 Cookbook Discover over 70 recipes that provide the solutions you need to know to face every challenge in Angular 2 head on

Arrow left icon
Product type Paperback
Published in Jan 2017
Publisher Packt
ISBN-13 9781785881923
Length 464 pages
Edition 1st Edition
Languages
Tools
Arrow right icon
Authors (2):
Arrow left icon
Matthew Frisbie Matthew Frisbie
Author Profile Icon Matthew Frisbie
Matthew Frisbie
Patrick Gillespie Patrick Gillespie
Author Profile Icon Patrick Gillespie
Patrick Gillespie
Arrow right icon
View More author details
Toc

Table of Contents (11) Chapters Close

Preface 1. Strategies for Upgrading to Angular 2 2. Conquering Components and Directives FREE CHAPTER 3. Building Template-Driven and Reactive Forms 4. Mastering Promises 5. ReactiveX Observables 6. The Component Router 7. Services, Dependency Injection, and NgModule 8. Application Organization and Management 9. Angular 2 Testing 10. Performance and Advanced Concepts

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
lock icon The rest of the chapter is locked
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $19.99/month. Cancel anytime