Angular Application Architecture

Created by Aysegul Yonet / twitter@AysSomething

Slides: bit.ly/ForwardJS-Angular2

  • Introduce yourself
    • Your name
    • Your Angular 1.x and 2.0 experience
    • What is the app you are building?
    • Anything you want to learn?
  • Node

    Verify that you are running at least node v6.x.x and npm 3.x.x by running node -v and npm -v in a terminal/console window.

About me

The Plan

  • Go through concepts and tools
  • Architecture overview
  • Build an app

  • ES6 / TypeScript
  • Custom Components / Services / Pipes
  • Data / Event binding
  • Passing Data between Component
  • Routing


npm -g list -depth=0
npm uninstall -g angular-cli @angular/cli
npm cache clean
npm install -g @angular/cli@latest
npm i -g typescript
				

What's new

  • Angular 4.0.0-rc.1
  • View Engine
  • TypeScript 2.1
  • Animation Package
  • Simplified APIs
  • Flexible router
  • Better integration with external libraries with Zone.js

How to update to ng --4


npm install @angular/{common,compiler,compiler-cli,core,forms,http,platform-browser,platform-browser-dynamic,platform-server,router,animations}@next --sav
                

Enhanced *ngIf syntax


Loading...
{{ user.name }}

Architecture Overview

data binding flow

Redux

data binding flow

TypeScript Playground


var notSure: any = 4;
notSure = "maybe a string instead";
notSure = false;
                


// For collections, there are typed arrays and generic arrays
let list: number[] = [1, 2, 3];
// Alternatively, using the generic array type
let list: Array<number> = [1, 2, 3];
let projects: ProjectType[] =
		

export type SlideElement = Text | Image | Lmv;
		

Advanced Types


var f1 = function(i: number): number { return i * i; }
// Return type inferred
var f2 = function(i: number) { return i * i; }
var f3 = (i: number): number => { return i * i; }
// Return type inferred
var f4 = (i: number) => { return i * i; }
// Return type inferred, one-liner means no return keyword needed
var f5 = (i: number) => i * i;

		

Data Binding


 
Hello, {{name}}!

function chartDirective () {
  return {
    restrict: ‘E’,
    scope: {
      data:"parentData"
    },
    link: link
  };
};

function link () {}
		

function chartDirective () {
  return {
    restrict: ‘E’,
    scope: {},
    bindToController: {
        data:"parentData"
    }
    link: link
  };
};

function link () {}
		


                

data binding flow

Property binding




I am a message

Event binding


 

		

Plunker

Two way data binding - not really!



		

Plunker

Local variable



{{ref.value}}

Plunker


  • {{message}}

Read more!

Recap

  • [Property] and (event) bindings are the public API of a directive.
  • Data flows into a directive via property bindings.
  • Data flows out of a directive via event bindings.
  • You can use property and event bindings to implement two-way bindings.
  • Angular provides syntax sugar for two-way bindings, interpolation, and passing constants.

Exercise

Plunker

  • Open plunker editor
  • Create a list of projects
  • Repeat the projects using *ngFor
  • Create a click event on repeated project to select the clicked item
  • Add an input field to add new projects

ES6 module syntax


//lib.js
export function square(x) {
 return x * x;
}
// main.js
import { square } from 'lib';
		

ES6 module syntax


//lib.js
export class Math{
  this.square(){}
}
// main.js
import { Math } from 'lib';
		

Bootstrapping


//main.ts
import {bootstrap} from 'angular2/platform/browser';
import {AppComponent} from './app.component';

bootstrap(AppComponent, []);
		

Bootstrapping in ES 5


document.addEventListener('DOMContentLoaded', function () {
  ng.platform.browser.bootstrap(MyAppComponent, [MyService, ng.core.provide(...)]);
});
		

Annotations


@Component({
    selector: 'post-list'
})
                    

ES 5 Annotations



(function(app) {
  app.AppComponent =
  ng.core.Component({
    selector: 'my-app',
    template: '

My First Angular 2 App

' }) .Class({ constructor: function() {} }); })(window.app || (window.app = {}));

Components




        	


@Component({
  selector: 'catstagram',
})

export Class Catstagram {
 constructor(){
  this.posts = [];
 }
}
                

@Component({
 selector: 'catstagram',
 templateUrl:'posts.html'
})

export Class Catstagram {
 constructor(){
   this.posts = [];
 }
}
                


@Component({
 selector: 'catstagram',
 templateUrl:'posts.html',
})

export Class Catstagram {
  constructor(){
    this.posts = [];
  }
}
        	


angular
  .module('app')
  .directive('catstagram', catstagramComponent);

  function catstagramComponent () {
     var directive =  {
       scope: {
         data:'=data'
       },
       link: createComponent
     }

     return directive;

      function createComponent () {}
}
                    


angular
  .module('app')
  .directive('catstagram', catstagramComponent);

    function catstagramComponent () {
      var directive =  {
        scope: {
          data:'=data'
         },
         controller:catController,
         link: createComponent
      }

      return directive;

      function createComponent () {}
      function catController (){...}
}
        	


@Component({
  selector: 'catstagram',
  templateUrl:'posts.html',
})

export Class Catstagram {
 @Input() data;
 constructor(){
  this.posts = this.data;
 }
}
        	

ng new ay-slides --style=sass
        

Step - 0

Github/Yonet/ay-slide

Life Cycle Hooks

@Input



        	

@Component({
    selector:'child',
    template:'

{{data}}

' }) export class ChildComponent { @Input() data; }

@Output



            

@Component({
    selector:'parent',
    template:''
})
export class ParentComponent {
    onChildEvent(ev){
        console.log('Event fired',ev);
    }
}
        	

@Input



            

@Component({
    selector:'child',
    template:''
})
export class ChildComponent {
    @Output childEvent = new EventEmitter();

    onClick(){
        this.childEvent.emit('hello!');
    }
}
            

Services


import { Injectable } from '@angular/core';

@Injectable()
export class DataService(){
 return [...];
}
                    

Routing


import { provideRouter, RouterConfig }  from '@angular/router';
import { HomeComponent, ListComponent } fromt './..';

                    

Route config


import { provideRouter, RouterConfig }  from '@angular/router';
const routes: RouterConfig = [
  {
    path: '',
    redirectTo: '/home',
    pathMatch: 'full'
  },
  {
    path: 'home',
    component: HomeComponent
},
{
  path: 'about',
  component: AboutComponent
}
];

export const appRouterProviders = [
  provideRouter(routes)
];

                    


import { ROUTER_DIRECTIVES } from '@angular/router';


                    

Plunker

Pipes

Slides

Additional resources

THE END

- Slides
- @AysegulYonet