Angular 2 for Angularjs

Angular 2 for AngularJs Developers

Now that Angular 2 is in Release Candidate someone moved our cheese! Let’s put on our running shoes. First off, let me start off by saying I have been writing Angular 2 for a year and a half now (actually, since this tweet) and writing AngularJS since the first stable release. Living through the Pre-Alpha, Alpha, and Beta I want to share what I quickly discovered in that time. We are going to see that everything’s changed, but nothing is different. Angular 2 is the Angular you have been looking for this is Angular 2 for AngularJS developers.

Terminology

  • For this article when I refer to AngularJS I’m speaking about Angular 1.x and Angular as both frameworks
  • Keep in mind that ES2015 was previously known as ES6
  • TypeScript is simply ES2015 + Optional Types
  • A Type is a class
  • An Observable is simply Collection + Time (more on this later in the video)

Bootstrapping

Both AngularJS and Angular 2 can be used with normal ES5, but most folks should be using use ES2015 with AngularJS and with Angular 2 it is highly recommended to use TypeScript.

It’s worth noting that our browsers today currently varies when it comes to ES2015 features that are implemented. Most of ES2015is able to run in Modern Browsers today while TypeScript was only meant to compile to JavaScript that can run natively in any browser (perhaps TypeScript will be able to run with Edge browser in a future without a compile step). We must have a solid build step to transform our code into ES5 for cross-platform support. Webpack and/or Gulp are the popular choices for the bundling, minifying, and building our application code. Once you have your preferred build process, we can bootstrap our application and jump into the code. If you’re in a hurry and just want to get started, check out our Angular 2 Webpack Starter and NG6-starter (AngularJS) on Github.

AngularJS

<!DOCTYPE html>
<html lang="en">
<head>
</head>
<body>
  <app>
    Loading...
  </app>
  <script src="bundle.js"></script>
</body>
</html>

Angular 2

<!DOCTYPE html>
<html lang="en">
<head>
</head>
<body>
  <app>
    Loading...
  </app>
  <script src="bundle.js"></script>
</body>
</html>

Our templates remain the same since we are also using the component pattern in AngularJS we are attaching our behavior to the <app> html element for our simple hello world component. With component driven architecture we compose our behavior by encapsulating them in a declarative way, in this case, our application.

AngularJS

npm install core-js // polyfills npm install angular // app

// Polyfills
import 'core-js';
// AngularJS
import angular, {bootstrap} from 'angular';

angular.module('app', [ ])
.component('app', {
  restrict: 'E',
  template: `<div>hello world</div>`,
  controller: class App {}
});

bootstrap(document, ['app']);

Angular 2

npm install zone.js core-js // polyfills npm install @angular/common @angular/compiler @angular/core @angular/http @angular/forms @angular/router @angular/platform-browser @angular/platform-browser-dynamic // angular 2

// polyfills
import 'core-js';
import 'zone.js/dist/zone';
// Angular 2
import {bootstrap} from '@angular/platform-browser';
import {Component} from '@angular/core';

@Component({
  selector: 'app',
  template: `<div>Hello World</div>`
})
class App {}

bootstrap(App);

The first thing you notice is the list of polyfills necessary for Angular 2.

  • core-js: an extremely modular suite of each ES2015 polyfills
  • zone.js/dist/zone-microtask: a way for JavaScript developers to keep track of our browser’s VirtualMachine

With both versions of Angular, we are importing our bootstrap function that will wire up dependency injection for our application.

AngularJS

import angular, {bootstrap} from 'angular';

Angular 2

import {bootstrap} from '@angular/platform-browser';
import {Component} from '@angular/core';

The difference here is that AngularJS the framework is assuming that we are working in the browser. With Angular 2 we can run JavaScript not only in our browsers but other environments such as the server or within a WebWorker.

AngularJS

angular.module('app', [ ])
.component('app', {
  restrict: 'E',
  template: `<div>hello world</div>`,
  controller: class App {}
});

Angular 2

@Component({
  selector: 'app',
  template: `<div>Hello World</div>`
})
class App {}

It seems like Angular 2 is taking more advantage of new features provided by ES2015 while AngularJS had to create its own abstraction to deal with modules. Notice how both versions of Angular we are providing metadata for Angular’s compiler the difference is how the framework handle our metadata. With Angular 2 we are attaching the metadata to our App class allowing us to pass around App while AngularJS we need to define our metadata within the angular.module abstraction. It’s also worth noting that Angular 2 makes full use of the decorator syntax (@decorator()).

Decorators

We can think of decorators as a function that changes the behavior of our classes.

function readonly(component) {
  component.writable = false;
  return component;
}

@readonly
class App {

}

In the example above we can attach properties and in this case we added writable. If we want to configure which properties we add which how to change the behavior, then we return a function.

function configMyDecorator(config) {

  function myAttachDecorator(component) {
    component.writable = config.writable;
    return component;
  }

  return myAttachDecorator;
}


@configMyDecorator({
  writable: false
})
class App {}

we can also use configMyDecorator without the @ syntax.

class App {}
configMyDecorator({
  writable: false
})(App);

So Angular 2 makes use of these decorators to attech metadata to our components that are classes.

Storing state

Modern web development is all about managing the state of our applications. In this example, we’re going to simplify state management by going over local state within our view. We’re talking more about view state that lives within the component that can also be called ViewModel since it’s a model that only exists for our View.

AngularJS

angular.module('app', [ ])
.component('app', {
  restrict: 'E',
  template: `<div>{{ app.myState }}</div>`,
  controller: class App {
    constructor() {
      this.myState = 'California';
    }
  }
});

Angular 2

@Component({
  selector: 'app',
  template: `<div>{{ myState }}</div>`
})
class App {
  myState = 'California';
}

TypeScript allows us to define initial state 'California' of our properties myState within the class App as syntactic sugar. Normally we have to write the value out manually inside our constructor as we did with AngularJS. If we use TypeScript with AngularJS, then conceptually nothing has changed other than writing half the code.

Event handlers

AngularJS allows us to register declaratively a listener to our DOM elements to expressions that invoke actions, methods that live in the current scope.

AngularJS

angular.module('app', [ ])
.component('app', {
  restrict: 'E',
  template: `<button ng-click="app.action($event)">Action</button>`,
  controller: class App {
    action(e) {
      console.log("never going to give you up", e);
    }
  }
});

Angular 2

@Component({
  selector: 'app',
  template: `<button on-click="action($event)">Action</button>`
})
class App {
  action(e) {
    console.log("never going to let you down", e);
  }
}

The only thing different here is the way we register our listener for our action. With AngularJS, the framework provided us with a set of core directives for each Native Browser event, but we found out that doesn’t scale well when we have to deal with custom events. With Angular 2 being able to register a listener for any event was preferred over reusing the directive API we use the on-(event name) (for example, on-submit, on-input, and on-change). Angular 2 allows us also to register an event for our element with a shorthand syntax that is the preferred syntax and one that I recommend.

Angular 2

@Component({
  selector: 'app',
  template: `<button (click)="action($event)">Action</button>`
})
class App {
  action(e) {
    console.log("I'm never gonna walk away", e);
  }
}

For example, (submit), (input), and (change) are used. The shorthand syntax allows us to quickly scan our templates for all events rather than guessing what the event might be of a random 3rd party directive. We can think of this approach from another perspective and that’s how we do it natively in our browser.

Native Browser

<button id="myButton" onclick="action()">Action</button>
<script>
  function action(e) {
    console.log("I'm always gonna have your back", e);
  }
  // we have a reference to our button because of id="myButton"
  // to emit the click event we simply invoke the native method
  window.myButton.click();
</script>

We are invoking the click event with the method click() so our shorthand syntax uses the same () to show us the event (click) will be invoked as (click)="action()". On (click) invoke action() or on-click="action()".

Change Detection

In AngularJS, we were introduced to the $digest loop that may have caused some confusion as to why it should be invoked. In Angular 2 we have been told that we no longer need to invoke the $digest loop anymore because of the magic from zone.js.

As a refresher the $digest loop is run whenever we want to reflect the changes of our ViewModels to the screen. Any data that is the glue to our View with bindings as {{ text }} will be checked one at a time if they have changed from its previous value. The concept is called Dirty Checking that was popularized by from Game Design and all (yes, React and Ember 2) of the Web Frameworks use it. We use dirty checking as an optimization for when we change the value of our ViewModel many times before we want to render it rather than rendering the View each time the View changed.

AngularJS

angular.module('home', [ ])
.component('home', {
  restrict: 'E',
  template: `
  <button ng-click="home.getData()">Get Server Data</button>
  <code><pre>{{ home.text | json }}</pre></code>
  `,
  controller: class Home {
    constructor($rootScope) {
      this.$rootScope = $rootScope;
      this.text = {};
    }
    getData(e) {
      // ajax
      setTimeout(() => {
        // async callback
        // change the value of our ViewModel
        this.text = {res: 'something else'};
        this.text = {res: 'data'};
        this.$rootScope.$digest(); // something changed
      }, 1000);
      //
      // $digest() ran by ng-click
    }
  }
});

Angular 2

@Component({
  selector: 'home',
  template: `
  <button (click)="getData()">Get Server Data</button>
  <code><pre>{{ text | json }}</pre></code>
  `
})
class Home {
  text = {};
  getData(e) {
    // ajax
    setTimeout(() => {
      // async callback
      this.text = {res: 'something else'};
      this.text = {res: 'data'};
      // zone.js tells triggers
    }, 1000);
  }
}

With AngularJS these $digest calls were abstracted away from us with the core directives such as ng-click which runs the $digest loop after it invokes our action. Then everyone kept saying to use $apply() rather than explaining what is happening under the hood and why it is there. The problem that everyone runs into is when we do something asynchronous. In our AngularJS example, we had to tell Angular manually to reflect our changes since the core directive ng-click already ran. With Angular 2 we have zone.js which will tell us when all the async calls within a given scope are done so we don’t have to Angular to trigger Change Detection. If you forget to include zone.js, we will have the same problem as we did in AngularJS where we have to trigger Change Detection manually for a component. If you want to understand zone.js more here’s a video of Miško Hevery explaining it.

https://youtu.be/V9Bbp6Hh2YE

Dependency Injection

In AngularJS, we have an amazing feature called Dependency Injection that allowed us not to worry about creating our dependencies in the correct order. We were inverting control over to the framework and following a particular convention. As a refresher, we can think of Dependency Injection simply as a huge key value store.

var di = {};

function MyService() {
  console.log("I'm at your service");
}
MyService.$inject = [];

var app = {
  Home: [ 'MyService', function(myservice) {
    console.log("I'm Home Component", myservice);
  }]
}

// during bootstrap
di['MyService'] = new MyService();

var controller = app.Home.pop();
var tokens = app.Home; // now just an array without the function;

var args = tokens.map(function(token) {
  return di[token];
});
// remember .apply(context, arguments) is JavaScript way of calling a function within another context as well as providing arguments as an array
controller.apply(controller, args);

There are some limitations here since the key, as we know in JavaScript Object Literal, can only be a string in ES5. With Angular 2 we use the Map type that allows us to use anything as the key and the most common use-case would be the Provider itself as the token.


class Service {
  constructor() {
    console.log('hello from service');
  }
}

var di = new Map();

var instance = new Service();

di.set(Service, instance);

di.get(Service); // returns instance

Angular 2 makes use of this and uses the reference to the class itself to represent the instance.

Services/Providers/Factory/Value/Constant?

In AngularJS, we had many different ways to create Services that were all Providers at the end of the day. In Angular 2, we changed the name of .service('name', Class) to {provide: Class, useClass: Class} and removed .constant (since we have const in ES2015). But we mostly will be using classes what we previously called .service in AngularJS. In both versions of Angular, we can call them Providers. (In this example, including the class Service itself without {provide: } will default to {provide: Service, useClass: Service};

AngularJS

angular.module('home', [ ])
.service('Service', class Service {
  constructor() {
    this._data = [];
  }
  getData() {
    return this._data;
  }
})
.component('home', {
  restrict: 'E',
  template: `<code><pre>{{ home.service.getData() }}</pre></code>`,
  controller: class Home {
    constructor(Service) {
      this.service = Service;
    }
  }
});

Angular 2

// ---- Provider ----
@Injectable()
class Service {
  _data = [];
  constructor() {

  }

  getData() {
    return this._data;
  }
}

// ---- Components ----
@Component({
  selector: 'home',
  providers: [ Service ],
  template: `<code><pre>{{ service.getData() }}</pre></code>`
})
class Home {
  // we are using TypeScript 'public' modifier
  constructor(public service: Service) {

  }
}

We are using a TypeScript feature called a public modifier that will declare our Type in our class as well the Type of the argument and set to the same property. Previously we got away with not declaring our type information because we were specifying default values of our properties outside our constructor. The concept might be familiar to developers coming from any other classical language as a way to remove boilerplate.

class Home {
  service: Service; // declare what instance type each property should be above our constructor
  constructor(service: Service) {
    this.service = service
  }
}

There’s a few things that are new in Angular 2, but conceptually they are the same. With Angular 2 again we have to say what providers Service are in this component Home then we inject our Service using our type Service as the token then we are also using TypeScript’s emitMetadata feature that essentially does what we did with ng-annotate in AngularJS. Let’s rewrite this component in ES5 to see what’s going on.

It’s worth noting that Injectable doesn’t do anything. It’s there to ensure that TypeScript correctly emits the metadata since the feature only works when a decorator is available on our class.

Angular 2

var Service = ng.
 Injectable().
 Class({
  constructor: [function() {
    this._data = [];
  }],
  getData: function() {
    return this._data;
  }
});

var Home = ng.
  Component({
    selector: 'home',
    providers: [ Service ],
    template: '<code><pre>{{ service.getData() }}</pre></code>'
  }).
  Class({
    constructor: [ Service, function(service) {
      this.service = service
    }]
  });

We can see that our constructor takes an array for us to declare what our dependencies are for our component with the last value being our function. We now know that we used an array to determine what tokens are used to be injected in our function. So let’s look at the output of TypeScript.

var Home = (function () {
  function Home(service) {
    this.prop = 'home';
    this.service = service;
  }
  Home = Reflect.decorate([
    Component({
      selector: 'home',
      providers: [ Service ],
      template: "<div>{{ prop }}</div>"
    }),
    Reflect.metadata('design:paramtypes', [ Service ])
  ], Home);
  return Home;
})();

The code is hard for us to read but it is the best way to write code for the JavaScript Virtual Machine to optimize our JavaScript and correctly reflect the Objects created within the Browser’s native language. Let us rewrite the TypeScript output to ES2015 so it is easier for us to grok.

class Home {
  prop = 'home';
  constructor(public service: Service) {

  }
}
var decorate = Component({
  selector: 'home',
  providers: [ Service ],
  template: `<div>{{ prop }}</div>`
});
var annotate = Reflect.metadata('design:paramtypes', [ Service ]);

decorate(Home);
annotate(Home);

Just like ng-annotate in AngularJS we are doing the same thing as outputting $inject to our controller we do the same using Reflect.metadata. TypeScript is giving us the type information Service of our arguments service: Service then Angular is using the type Service as the token for our Dependency Injection system. In other words, decorators are just functions that attach metadata to our classes for Angular 2 to read as the token to pass on to our Dependency Injection system.

Component composition

With AngularJS, we compose our components nearly the same way as we do with Angular 2.

AngularJS

angular.module('app', [ ])
.component('navbar', {
  restrict: 'E',
  template: `<div>{{ navbar.text }}</div>`,
  controller: class Navbar {
    constructor() {
      this.text = 'navbar';
    }
  }
})
.component('footer', {
  restrict: 'E',
  template: `<div>{{ footer.text }}</div>`,
  controller: class Footer {
    constructor() {
      this.text = 'footer';
    }
  }
})
.component('home', {
  restrict: 'E',
  template: `
  <navbar></navbar>
  <div>{{ home.text }}</div>
  <footer></footer>
  `,
  controller: class Home {
    constructor() {
      this.text = 'home'
    }
  }
});

Angular 2

@Component({
  selector: 'navbar',
  template: `<div>{{ text }}</div>`
})
class Navbar {
  text = 'navbar';
}
@Component({
  selector: 'footer',
  template: `<div>{{ text }}</div>`
})
class Footer {
  text = 'footer';
}
@Component({
  selector: 'home',
  directives: [Navbar, Footer],
  template: `
  <navbar></navbar>
  <div>{{ text }}</div>
  <footer></footer>
  `
})
class Home {
  text = 'home';
}

With Angular 2 we have to specify which directives live in our template. That’s because the metadata lives on our component’s which is just a regular JavaScript class. With AngularJS, we had a module system that managed with everything else which allowed us to check globally in our application if we have the directive. (There are ways to have the same effect in Angular 2 that would provide us with the same workflow but more on that in the next article)

Scope, Bindings, and Properties

AngularJS had an idea of $scope and $rootScope are the ViewModel to our views since they represent the current state of our view. Another way to think of $scope is how our browser works. If you ever tried to run toString() in the console you will see "[object Window]" because our scope currently is window (and window is referncing itself). So when we create a new scope (in this sense)

function Scope() {
}
var scope = new Scope();
scope.toString();

we get "[object Object]" but we can change the value.

function Scope() {
  this.toString = function() {
    return 'oh hai';
  }
}
var scope = new Scope();
scope.toString();

In our templates, the scope becomes the a section of our app linked to our controller in AngularJS. When we use controllerAs syntax, we are doing the same as window.toString(). We did this because it is hard to see clearly what the current scope is without thinking about it first. When we’re dealing with many scopes within a template, we shouldn’t have to think about it.

<div ng-controller="top">
  {{ prop }}
  <div ng-controller="middle">
    {{ prop }}
    <div ng-controller="bottom">
      {{ prop }}
    </div>
  </div>
</div>

The template above is hard to quickly reason about where the value of prop is coming from within these scopes. When we switched to controlerAs then it should solve our problem.

<div ng-controller="top as vm">
  {{ vm.prop }}
  <div ng-controller="middle as vm">
    {{ vm.prop }}
    <div ng-controller="bottom as vm">
      {{ vm.prop }}
    </div>
  </div>
</div>

Wait, we still have the same problem so why are we calling everything vm thinking it will solve our problems.

<div ng-controller="top">
  {{ top.prop }}
  <div ng-controller="middle">
    {{ middle.prop }}
    <div ng-controller="bottom">
      {{ bottom.prop }}
    </div>
  </div>
</div>

Correctly naming our controller will make it very clear as to which variable is referencing what value. It’s very transparent to know what our references are which is why we switched to controllerAs syntax. We can also mix scopes and still be able to reason quickly about where the correct references are points to.

<div ng-controller="top">
  {{ top.prop }}
  <div ng-controller="middle">
    {{ top.prop }}
    {{ middle.prop }}
    <div ng-controller="bottom">
      {{ top.prop }}
      {{ middle.prop }}
      {{ bottom.prop }}
    </div>
  </div>
</div>

AngularJS also provides us with a way to organize our View logic so we won’t have to think about everything else in our app. By creating a .component which will create a new scope for our code to live in we are isolating View logic to the suitable component. We can imagine of a component as a mini Angular app. We have to ensure View logic that the correct concern with that part of the View only lives in within that component. A good example of View logic is toggling the loading bar within a button or triggering a global loading bar with a Service.

angular.module('app', [ ])
.component('bottom', {
  restrict: 'E',
  bindings: {
    top: '=',
    middle: '='
  },
  template: `
  {{ top.prop }}
  {{ middle.prop }}
  {{ prop }}
  `,
  controller: class Bottom {
    constructor() {
      this.prop = 'bottom';
    }
  }
})
.component('middle', {
  restrict: 'E',
  bindings: {
    top: '='
  },
  template: `
  <bottom top="middle.top" middle="middle"></bottom>
  `,
  controller: class Middle {
    constructor() {
      this.prop = 'middle';
    }
  }
})
.component('top', {
  restrict: 'E',
  template: `
  <middle top="top"></middle>
  `,
  controller: class Top {
    constructor() {
      this.prop = 'top'
    }
  }
});

With this AngularJS example, we can separate our View logic within the correct component. Doing so allows us to lower the amount of mental overhead of the state of our application since we only need to worry about the current component and the data that’s coming in. With Angular 2 let’s go over how we compose our components.

@Component({
  selector: 'bottom',
  template: `
  {{ prop }}
  `
})
class Bottom {
  prop = 'bottom';
}
@Component({
  selector: 'middle',
  directives: [ Bottom ],
  template: `
  <bottom></bottom>
  {{ prop }}
  `
})
class Middle {
  prop = 'middle';
}
@Component({
  selector: 'top',
  directives: [ Middle ],
  template: `
  <middle></middle>
  {{ prop }}
  `
})
class Top {
  prop = 'top';
}

We can clearly see what the prop is for each component because we’re not viewing all of the components at the same time. So then how do we pass values around from parent components? We do it by specifying our inputs metadata that is simular to bindings in AngularJS.

@Component({
  selector: 'bottom',
  inputs: [
   'topProp',
   'middleProp'
  ],
  template: `
  {{ topProp }}
  {{ middleProp }}
  {{ prop }}
  `
})
class Bottom {
  topProp = '';
  middleProp = '';
  prop = 'bottom';
}

@Component({
  selector: 'middle',
  directives: [Bottom],
  inputs: [
    'topProp'
  ],
  template: `
  <bottom [topProp]="topProp" [middleProp]="prop" ></bottom>
  {{ topProp }}
  {{ prop }}
  `
})
class Middle {
  top = '';
  prop = 'prop';
}
@Component({
  selector: 'top',
  directives: [Middle],
  template: `
  <middle [topProp]="prop"></middle>
  {{ prop }}
  `
})
class Top {
  prop = 'top';
}

What we’re doing is creating a new scope with each new component and remember that our scope is the component itself. For example

var top = new Top();
var middle = new Middle();
var bottom = new Bottom();

And how would we dynamically set the properties of an instance in JavaScript? With the bracket notation.

var top = new Top();

var middle = new Middle();
middle['topProp'] = top.prop;

var bottom = new Bottom();
bottom['topProp'] = middle.topProp;
bottom['middleProp'] = middle.prop;

So when we see the syntax <bottom [topProp]="topProp"></bottom> it’s similar to how we do it in JavaScript as bottom['topProp'] = middle.topProp; We also also use another syntax which is the preferred and recommended version using the @Input() decorator which attaches the same inputs metadata.

@Component({
  selector: 'bottom',
  template: `
  {{ topProp }}
  {{ middleProp }}
  {{ prop }}
  `
})
class Bottom {
  @Input() topProp = '';
  @Input() middleProp = '';
  prop = 'bottom';
}

@Component({
  selector: 'middle',
  directives: [Bottom],
  template: `
  <bottom [topProp]="topProp" [middleProp]="prop" ></bottom>
  {{ topProp }}
  {{ prop }}
  `
})
class Middle {
  @Input() topProp = '';
  prop = 'prop';
}
@Component({
  selector: 'top',
  directives: [Middle],
  template: `
  <middle [topProp]="prop"></middle>
  {{ prop }}
  `
})
class Top {
  prop = 'top';
}

Data Binding

One of the biggest differences between the two frameworks is data binding. In AngularJS, the default is two-way with an option to use one-way-one-time. With Angular 2 we have one-way binding, but we have directives that can help with two-way data binding. It turns out that we only need two-way data binding for forms while everywhere else usually remains static.

AngularJS

angular.module('app', [ ])
.component('middle', {
  restrict: 'E',
  bindings: {
    top: '='
  },
  template: `
   {{ top.prop }}
   <button ng-click="changeData()">change</button>
  `,
  controller: class Middle {
    changeData() {
      this.top.prop = 'somethingNew';
    }
  }
})
.component('top', {
  restrict: 'E',
  template: `
  <middle top="top"></middle>
  {{ top.prop }}
  `,
  controller: class Top {
    constructor() {
      this.prop = 'top'
    }
  }
});

Angular 2

@Component({
  selector: 'middle',
  template: `
  {{ topProp }}
  <button (click)="changeData()">change</button>
  `
})
class Middle {
  @Input() topProp = '';

  changeData() {
    this.topProp = 'somethingNew';
  }
}
@Component({
  selector: 'top',
  directives: [Middle],
  template: `
  <middle [topProp]="prop"></middle>
  {{ prop }}
  `
})
class Top {
  prop = 'top';
}

In Angular 2 when we invoke changeData() we are able to see the value changed only for Middle component not in Top component. This is due to one-way data flow where we get the initial state from the top-level-components to be passed down to child components. Doing so gives us faster Change Detection since we’re able to optimize which components should be updated and which ones should not. While in AngularJS we can see that data is being reflected in both components because of two-way data binding. We can update our parent component by emitting events from our child components. We can do this by hooking into native events that bubble up

@Component({
  selector: 'middle',
  template: `
  {{ topProp }}
  <button>change</button> <!-- emits 'click' event when clicked by the user -->
  `
})
class Middle {
  @Input() topProp = '';
}
@Component({
  selector: 'top',
  directives: [Middle],
  template: `
  <middle [topProp]="prop" (click)="changeData()"></middle>
  {{ prop }}
  `
})
class Top {
  prop = 'top';
  changeData() {
    this.topProp = 'somethingNew';
  }
}

When we click on our button element, we are invoking changeData() in the top-level-component Top where the application state is triggering Change Detection and where the state is being stored. The concept is called Unidirectional Data Flow where data, also known as application state, in our view flows one way (down to child components). We can also use providers to store and update our data.

// function that does nothing when invoked
function noop {}

// ---- Provider ----
@Injectable()
class Service {
  _data = {};
  _updateCallback = noop;
  getLatest() {
    return this._data;
  }
  onUpdate(callback) {
    this._updateCallback = callback;
  }
  update(value) {
    this._data = value; // set current value
    this._updateCallback(this._data); // invoke current update function
  }
}

// ---- Components ----
@Component({
  selector: 'middle',
  template: `
  {{ topProp }}
  <button (click)="changeData()">change</button>
  `
})
class Middle {
  @Input() topProp = '';
  constructor(public service: Service) {

  }

  changeData() {
    var newData = 'somethingNew';
    this.service.update(newData);
  }
}
@Component({
  selector: 'top',
  directives: [ Middle ],
  providers: [ Service ],
  template: `
  <middle [topProp]="prop"></middle>
  {{ prop }}
  `
})
class Top {
  prop = '';
  constructor(public service: Service) {
    // We want to update our ViewModel
    this.service.onUpdate(data => {
      this.prop = data;
    });
    this.service.update('top');
  }

}

In this example, we are registering a callback with our Service with onUpdate then updating our initial view with "top". The problem here is that we’re going to end up recreating an EventEmitter within our service. If we continue down this path, we need to change _updateCallback to an array for many callbacks. The common pattern we’re seeing here why an EventEmitter becomes baked into Angular 2 and in fact not just any EventEmitter it’s an Observable which is an ES7 spec. Let’s refactor our example to use an Observable.

import {Observable} from 'rxjs/Rx';

// ---- Provider ----
@Injectable()
class Service {
  _data = {};
  _updateObservable = noop;
  onUpdate() {
    return new Observable(observer => {
      this._updateObservable = (data) => {
        // `.next()` means the next value in our stream of data;
        observer.next(data);
      }
    });
  }
  getLatest() {
    return this._data;
  }
  update(value) {
    this._data = value;
    this._updateObservable(this._data);
  }
}

// ---- Components ----
@Component({
  selector: 'middle',
  template: `
  {{ topProp }}
  <button (click)="changeData($event.target.value)">change</button>
  `
})
class Middle {
  @Input() topProp = '';
  constructor(public service: Service) {

  }

  changeData(newData) {
    this.service.update(newData);
  }
}
@Component({
  selector: 'top',
  directives: [ Middle ],
  providers: [ Service ],
  template: `
  <middle [topProp]="prop"></middle>
  {{ prop }}
  `
})
class Top {
  prop = '';
  constructor(public service: Service) {
    // We want to update our ViewModel
    this.service.onUpdate().subscribe(data => {
      this.prop = data;
    });
    this.service.update('top');
  }

}

Great so now we’re using the new Observable feature with ES7 we can use the EventEmittter provided by Angular. The Angular Team decided to stick with upcoming standards by baking in Observable just as they did in AngularJS with Promises. With the Observable we are using rxjs‘s Subject (alias as EventEmitter in Angular 2)and Angular 2’s @Output decorator. A Subject allows us to produce values after it’s created rather than Observable where we had to expose a function of it’s internals. To learn more about Observable and RxJS you can watch this video by Jafar Husain

https://youtu.be/XE692Clb5LU?t=26s

// ---- Provider ----
@Injectable()
class Service {
  _data = {};
  getLatest() {
    return this._data;
  }
  update(value) {
    return this._data = value;
  }
}

// ---- Components ----
@Component({
  selector: 'middle',
  template: `
  {{ topProp }}
  <button (click)="changeData($event)">change</button>
  `
})
class Middle {
  @Input() topProp = '';
  @Output() update = new EventEmitter();  // our Rx Subject subscription maintained by Angular
  changeData($event) {
    this.update.emit('somethingNew');
  }
}
@Component({
  selector: 'top',
  directives: [ Middle ],
  providers: [ Service ],
  template: `
  <middle [topProp]="prop" (update)="changeData($event)"></middle>
  {{ prop }}
  `
})
class Top {
  prop = '';
  constructor(public service: Service) {
    this.service.update('top');
  }
  changeData(data) {
    this.service.update(data); // update our state
    this.prop = this.service.getLatest(); // update our ViewModel
  }


}

Great! We’re able to create a custom event using our EventEmitter instance and passing a new value to it using .emit(). Then receiving our data with the $event as a local variable. Then we’re invoking changeData in our top-level component to update our service and view. If you’re asking “can we make it easier?” then I’ll have to answer yes we can. Let’s refactor again.

// ---- Provider ----
@Injectable()
class Service {
  _data = {};
  getLatest() {
    return this._data;
  }
  update(value) {
    return this._data = value;
  }
}

// ---- Components ----
@Component({
  selector: 'middle',
  template: `
  {{ topProp }}
  <button (click)="update.emit('somethingNew')">change</button>
  `
})
class Middle {
  @Input() topProp = '';
  @Output() update = new EventEmitter();

}
@Component({
  selector: 'top',
  directives: [ Middle ],
  providers: [ Service ],
  template: `
  <middle [topProp]="prop" (update)="prop = service.update($event)"></middle>
  {{ prop }}
  `
})
class Top {
  prop = this.service.update('top');
  constructor(public service: Service) {

  }
}

There are many different ways we can update our View now that we have more control over how our components ViewModel are updated. We can completely change the way Angular detects changes to fit our needs. Unlike AngularJS where we had to control our two-way data flow in Angular 2, it’s simpler to deal with data.

Forms

One of the best things about Angular was two-way data binding with forms. It turns out we want to persevere user state, or user inputted data, on the page and not update our models until our customer is ready to save it. With Angular 2 we have form directives to give us our ng-model.

AngularJS

angular.module('home', [ ])
.component('home', {
  restrict: 'E',
  template: `
  <input ng-model="home.text">
  <code><pre>{{ home.text }}</pre></code>
  `,
  controller: class Home {
    constructor() {
      this.text = '';
    }
  }
});

Angular 2

@Component({
  selector: 'home',
  directives: [ FORM_DIRECTIVES ],
  template: `
  <input name="myText" [(ngModel)]="text">
  <code><pre>{{ text }}</pre></code>
  `
})
class Home {
  text = '';
}

There are really three things to take notice here it’s name="myText", [(ngModel)] and FORM_DIRECTIVES. FORM_DIRECTIVES is an array of directives nothing more nothing less.

var FORM_DIRECTIVES = [
  // ... other directives
  NgModel
  // ... other directives
];

Rather than including the name of our angular.module('FORM_DIRECTIVES', []) in Angular 2 we just use an array. The next thing is [(ngModel)]. It turns out data-binding is both get data and set data so let’s look at another example.

@Component({
  selector: 'home',
  template: `
  <input [value]="text" (input)="text = $event.target.value">
  <code><pre>{{ text }}</pre></code>
  `
})
class Home {
  text = '';
}

For our <input> tag we are both setting value as text properties and in the event input event we are setting the property test to the value of the event object. For more information about form interaction and ways to persist them we will cover them in our one of our future posts.

Dynamic elements

In both versions of Angular, we have core directives that change the structure of our views. In Angular 2 we call them Structural Directives.

AngularJS

angular.module('app', [ ])
.component('sidebar', {
  restrict: 'E',
  bindings: {
    title: '=',
    items: '='
  },
  template: `
    <div class="sidebar">
      <h1>{{ sidebar.title }}</h1>
      <ul>
        <li ng-repeat="item in sidebar.items">
          {{ item }}
        </li>
      </ul>
    </div>
  `,
  controller: class Home {
  }
});
.component('app', {
  restrict: 'E',
  template: `
    <div>
      <sidebar
        title="app.state.title"
        items="app.state.items"
      ></sidebar>
    </div>
  `,
  controller: class App {
    constructor() {
      this.state = {
        title: 'Side bar',
        items: ['home', 'profile', 'settings']
      };
    }
  }
});

Angular 2

@Component({
  selector: 'sidebar',
  template: `
    <div class="sidebar">
      <h1>{{ title }}</h1>
      <ul>
        <li *ngFor="let item of items">
          {{ item }}
        </li>
      </ul>
    </div>
  `
})
class Sidebar {
  @Input() title = '';
  @Input() items = [];
}

@Component({
  selector: 'app',
  directives: [
    Sidebar
  ],
  template: `
    <div>
      <sidebar
        [title]="state.title"
        [items]="state.items"
      ></sidebar>
    </div>
  `,
})
class App {
  state = {
    title: 'Side bar',
    items: ['home', 'profile', 'settings']
  };
}

Like AngularJS, Angular 2 has a directive we can use to repeat over data and create elements. The ngFor directive is similar to ng-repeat. Because Angular 2 uses <template> to clone element, for performance reasons, they created a shorthand to expand micro-syntax with *. That’s why we use *ngFor. We are also using refs (references) with the # or let followed by a variable name to create a local variable in the template to get access to our raw DOM node. We can reason about why the Angular Team chooses # syntax as a local variable reference. Including an id attribute to an element gives us access to that element globally in our Browser. We can get a reference to our div (<div id="myElement"></div>) with window.myElement (if you didn’t know about this then you should try it out). Like ES2015 iterators, we are using a for of loop to iterate over the collection, assigning the current element to the local variable we created.

<div class="sidebar">
  <h1>{{ title }}</h1>
    <ul>
      <template ngFor #item [ngForOf]="items">
        <li>{{ item }}</li>
      </template>
    </ul>
 </div>

Styles

There are many ways to add styles to our components. With build tools like Webpack, that lists grows longer and longer. Having CSS encapsulation is an important part of creating flexible components since it decouples our component from the application as a whole. These styles are scoped to our component by prepending a unique name to our CSS to avoid CSS collision.

@Component({
  selector: 'app',
  // encapsulation: ViewEncapsulation.Emulated, // our default setting
  styles: [`
    .app {

    }
    .actions {

    }
    .button {

    }
  `],
  template: `
    <div class="app">
      <div class="actions">
        <button class="button">click</button>
      </div>
    </div>
  `,
})
class App {}

With managing styles, we didn’t have anything in AngularJS, but now we do in Angular 2 with ShadowDOM emulation. We can configure our component by setting the encapsulation property on the @Component decorator that allows us to change how our styles scoping behaves. First we need to import ViewEncapsulation. There are three values that we could use. The default for components is ViewEncapsulation.Emulated which outputs namespaces of our class next to our styles. ViewEncapsulations.Native uses the Native ShadowDOM (when that is ready). ViewEncapsulation.None removes any fancy style scope in our components.

In fact, a typical trend that I’m noticing is that Angular 2 seems like twice the framework with half the application code to maintained compared to AngularJS.

Angular 2 for AngularJS developers

Well, it turns out that everything’s changed, but nothing is different. When AngularJS released 6+ years ago, we didn’t know best practices for directives or patterns that would simplify our workflow. Now we do, now Angular 2 is the same Angular framework that we all know and love. In fact, I have been noticing, is that Angular 2 provides us with twice the functionality with better core concepts allowing us to reason about our application in a more intuitive manner that usually results in half the application code compared to AngularJS. If you’re migrating an application from AngularJS to Angular 2, then you’re able to see which patterns are common in Angular 2. Stay tuned for our next post when we dive deeper into Angular 2 and showing the power and flexibility that our new framework provides. Angular 2 allows us to do more advanced patterns with less code just as AngularJS did in the past. With Angular 2, it is much easier to reason about our application. With TypeScript, it is more obvious as your team/codebase gets larger that our application will be more maintainable. With the introduction of core support for TypeScript, we have features such as typo checks and auto completion that will have us forget about typical problems we run into with ES5. We have all been there debugging code that was simply a typo. If you like to learn more about Angular 2 as soon as possible, please attend one of our workshops or inquire for corporate training.

Follow us on Twitter @AngularClass Like us on Facebook AngularClass Join our Slack chat room Follow me on Twitter @gdi2290

Related Posts

Angular 2 for React Developers

Angular is here, the time has come for us to drop everything and learn something new, again. The good news is, like React and Angular 1.x, Angular 2 is here to stay for a while so it’s a good investment to become productive with this new framework…

Create a simple reactive store for Angular 2

Angular 2 uses observables for many features and has a peer dependency on RxJs for its robust API around observables. The community has adopted a single store approach for dealing with state in modern applications. Let’s build a store for our Angular…
twitter tweet