building a tv show with angular, bootstrap, and web services

Post on 13-Jan-2017

196 Views

Category:

Technology

5 Downloads

Preview:

Click to see full reader

TRANSCRIPT

Building a TV Showwith Angular, Bootstrap, and Web Services

David Giard• Senior Technical Evangelist, Microsoft• @DavidGiard• davidgiard.com• dgiard@Microsoft.com• channel9.msdn.com/blogs/technology-and-friends

Single Page Applications

Traditional Web App

HTML Page

Click me!

Server

Request

Response

Thank you, David!

Single Page App

HTML Page

Click me!

Server

Request

Response

Thank you, David!

{‘name’: ‘David’}

Architecture

Web Service

Database

Web APIAngular 2TypeScriptBootStrap

SinglePageApp

Function Tool

Web Service Web API

Database SQL Server

Single Page Application Angular 2 & TypeScript

Styling Bootstrap

Web API

Web API Routing

public class ValuesController : ApiController { public IEnumerable<string> Get() {…} public string Get(int id) {…} public void Post ([FromBody]string value) {… } public void Put (int id, [FromBody]string value) {..} public void Delete (int id) {…} }

http://..../api/valuesHTTP Verb

GETPOSTPUT

DELETE

Angular 2and

TypeScript

Angular• SPA Framework• Open Source• Data Binding• Components• Modularize

TypeScript• Open Source• Superset of JavaScript• Transpiles to JavaScript

TypeScriptfoo.ts foo.js

Transpile

foo.map

Transpile

TypeScript Transpiling• Command Line: tsc or tsc -w• Grunt, Gulp, etc.• Visual Studio

TypeScript Advantages• Productivity• Static Type Analysis• Language Tool Support• Better management of large codebases

Type Checkingvar num1 = 5;var num2 = 10;…

num2=“Fish”;…

var sum = num1 + num2;

Type Checkingvar num1: number = 5;var num2 : number = 10;…

num2=“Fish”;…

var sum: number = num1 + num2;

tsconfig.json{ "compilerOptions": { "target": "es5", "module": "system", "moduleResolution": "node", "sourceMap": true, "emitDecoratorMetadata": true, "experimentalDecorators": true, "removeComments": false, "noImplicitAny": false }, "exclude": [ "node_modules", "typings/main", "typings/main.d.ts" ]}

typings.json{

"ambientDependencies": {

"es6-shim": "github:DefinitelyTyped/DefinitelyTyped/es6-shim/es6-shim.d.ts#7de6c3dd94feaeb21f20054b9f30d5dabc5efabd",

"jasmine": "github:DefinitelyTyped/DefinitelyTyped/jasmine/jasmine.d.ts#5c182b9af717f73146399c2485f70f1e2ac0ff2b"

}

}

Angular 2

Key Parts of Angular• Modules• Components• Templates• Directives• Services• Routing• Http

Modules

Modules• Built into Angular 2• Makes it easier to split code into smaller pieces• Import one module into another• Export module to make it available for import

Modulesimport {Component} from 'angular2/core';@Component({ selector: 'my-app', template: '<h1>Hello World</h1>'})export class AppComponent { }

Available outside this

module

Use exported module

In this module

Components

Components• Class (properties & methods)• Decorated with @Component• Template• Selector• Imported references

Templates and Selectors

Templates and Selectorsimport {Component} from 'angular2/core';

@Component({ selector: 'my-app', template: '<h1>Hello World</h1>'})export class AppComponent { }

Selector@Component({ selector: 'my-app', template: '<h1>Hello World</h1>'})export class AppComponent { }

<my-app>Loading...</my-app>

Templates@Component({ selector: 'my-app', template: '<h1>Hello World</h1>'})export class AppComponent { }

<my-app>Loading...</my-app>

Output

Loading…

Templates@Component({ selector: 'my-app', template: '<h1>Hello World</h1>'})export class AppComponent { }

<my-app>Loading...</my-app>

Output

Hello World

Templates: Multi-Line<my-app>Loading...</my-app>

Output

Hello WorldWelcome

@Component({ selector: 'my-app', template: `

<h1>Hello World</h1><div>Welcome!</div>`

})export class AppComponent { }

Templates: External file@Component({ selector: 'my-app', templateurl: 'myApp.html'})export class AppComponent { }

<my-app>Loading...</my-app>

Output

<h1>Hello World</h1><div>

Welcome!</div>

myApp.html

Hello WorldWelcome

@Component({ selector: 'my-app', templateurl: 'myApp.html'})export class AppComponent { }

Bootstrapping<my-app>Loading...</my-app>

<script>…System.import('app')</script>

import {AppComponent} from './app.component';

bootstrap(AppComponent);Main.ts

= bootstrap file

Directives

Directives• Allow you to attach behavior to DOM elements

Directives• *ngFor• *ngIf• ngSwitch• ngClass• Custom Directives

*ngfor

<div *ngFor="#cust of customers"> {{cust.lastName}}, {{cust.firstName}}</div>

var customers: Customer[] = [ { "id": 1, "firstName": "David", "lastName" : "Giard" }, { "id": 2, "firstName": "Bill", "lastName": "Gates" }, { "id": 3, "firstName": "Steve", "lastName": "Ballmer" }, { "id": 4, "firstName": "Satya", "lastName": "Nadella" }];

Giard, DavidGates, BillBallmer, SteveNadella, Satya

*ngIf• Syntax: *ngif="condition"• Removes element from DOM if condition is not “truthy”

*ngIf

<div><button (click)="clicked()">Toggle</button><div *ngIf="show">

Can you see me?</div>

</div>

export class AppComponent {show: boolean = true; clicked() {this.show = !this.show; }

}

ToggleCan you see me?

*ngIf

<div><button (click)="clicked()">Toggle</button><div *ngIf="show">

Can you see me?</div>

</div>

export class AppComponent {show: boolean = true; clicked() {this.show = !this.show; }

}

ToggleCan you see me?

LifeCycle Hooks• OnInit• OnChanges• OnDestroy

OnInit

export class foo implements OnInit {...ngOnInit(){...}

}

Services

Services• Class containing logic• Shared Code: Used by components or other services• Substitutable Objects• Dependency Injection

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

@Injectable()export class CustService { getCustomers() { return customers; }}

var customers: Customer[] = [ { "id": 1, "firstname": "David", "lastname": "Giard" }, { "id": 2, "firstname": "Bill", "lastname": "Gates" }, { "id": 3, "firstname": "Steve", "lastname": "Ballmer" }, { "id": 4, "firstname": "Satya", "lastname": "Nadella" }];

CustomerService.ts

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

@Injectable()export class CustService { getCustomers() { return customers; }}…

CustomerService.ts

import { OnInit } from '@angular/core';import {CustService} from CustomerService

export class AppComponent implements OnInit {

ngOnInit() { this.customers = this.customerService.getCustomers(); } constructor(private customerService:CustService) { }}

Data Binding• Simple Binding• One-Way Property Binding• 2-Way Property Binding• Event Binding

1-Way Data Binding• Square brackets around property• []

1-Way Data Binding@Component({ selector: 'my-app', template: ‘<button [disabled]=" dataNotChanged">Save</button>’})export class AppComponent {

dataNotChanged= true;}

Save

1-Way Data Binding@Component({ selector: 'my-app', template: ‘<button [disabled]=" dataNotChanged">Save</button>’})export class AppComponent {

dataNotChanged = true;}

Save

1-Way Data Binding@Component({ selector: 'my-app', template: ‘<button [disabled]=" dataNotChanged">Save</button>’})export class AppComponent {

dataNotChanged = false;}

Save

1-Way Data Binding• Double curly braces around data• {{}}

1-Way Data Binding@Component({ selector: 'my-app', template: '<h1>Hello World</h1>'})export class AppComponent {

id=1;customerFirstName='David';customerLastName='Giard';

}

1-Way Data Binding@Component({ selector: 'my-app', template: '<h1>Hello {{customerFirstName}}</h1>'})export class AppComponent {

id=1;customerFirstName='David';customerLastName='Giard';

}

1-Way Data Binding

Hello David

1-Way Data Binding@Component({ selector: 'my-app', template: '<h1>Hello {{customer.FirstName}}</h1>'})export class AppComponent {

id=1;customer: Customer = {FirstName='David';LastName='Giard';}

}export class Customer{

FirstName: string;LastName: string;

}

1-Way Data Binding@Component({ selector: 'my-app', template: `<h1>{{customer.FirstName}} Details</h1><div>First: {{customer.FirstName}}</div><div>Last: {{customer.LastName}}`})export class AppComponent {

id=1;customer: Customer = {FirstName='David';LastName='Giard';}

}David DetailsFirst: DavidLast: Giard

2-Way Data Binding@Component({ selector: 'my-app', template: `<h1>{{customer.FirstName}} Details</h1><div>First: <input [(ngModel)]="customer.FirstName" </div><div>Last: <input [(ngModel)]="customer.LastName" </div>`})export class AppComponent {

id=1;customer: Customer = {FirstName='David';LastName='Giard';}

}

2-way data binding

David DetailsDavid

Giard

First:

Last:

1-way data binding

2-Way Data Binding@Component({ selector: 'my-app', template: `<h1>{{customer.FirstName}} Details</h1><div>First: <input [(ngModel)]="customer.LastName" </div><div>Last: <input [(ngModel)]="customer.FirstName" </div>`})export class AppComponent {

id=1;customer: Customer = {FirstName='David';LastName='Giard';}

}D Details

D

Giard

First:

Last:

2-Way Data Binding@Component({ selector: 'my-app', template: `<h1>{{customer.FirstName}} Details</h1><div>First: <input [(ngModel)]="customer.LastName" </div><div>Last: <input [(ngModel)]="customer.FirstName" </div>`})export class AppComponent {

id=1;customer: Customer = {FirstName='David';LastName='Giard';}

}Da Details

Da

Giard

First:

Last:

2-Way Data Binding@Component({ selector: 'my-app', template: `<h1>{{customer.FirstName}} Details</h1><div>First: <input [(ngModel)]="customer.LastName" </div><div>Last: <input [(ngModel)]="customer.FirstName" </div>`})export class AppComponent {

id=1;customer: Customer = {FirstName='David';LastName='Giard';}

}Dan Details

Dan

Giard

First:

Last:

Events binding<control (eventname)="methodname(parameters)">

click event<control (click)="methodtocall(parameters)">

e.g.,<div (click)="onClick(customer)">

click@Component({ selector: 'my-app', template: `<h1 (click)="onClick (customer)">{{customer.FirstName}} Details</h1><div>First: <input [(ngModel)]="customer.LastName" </div><div>Last: <input [(ngModel)]="customer.FirstName" </div>`})export class AppComponent {

id=1;customer: Customer = {FirstName='David';LastName='Giard';}onClick(cust: Customer) { alert ("You Selected " + customer.FirstName); }

}

Routing

Routing• Load components dynamically into page• Link via URL• Client-side• Step 1: Bootstrap array of routes

Routingconst routes: RouterConfig = [ { path: 'foo', component: FooComponent }, { path: 'bar', component: BarComponent },];

export const appRouterProviders = [ provideRouter(routes)];

import { appRouterProviders } from './app.routes';

bootstrap( AppComponent, [ appRouterProviders]);

<a [routerLink]="[/foo']">Foo</a><a [routerLink]="[/bar']">Bar</a>

<router-outlet></router-outlet>

app.routes.ts

main.tsBootstrap routes

User clicks “Foo” link

FooComponent loaded in router-outlet

HTTP

HTTP

import {Http } from '@angular/http';

...

this.http.get(webServiceUrl);

bootstrap(AppComponent, [HTTP_PROVIDERS,

]);

main.ts

Component

Observables

Observables

Observable<T>

Function

Subscribe

Data

ObservablesgetEpisodes(): Observable<IEpisode[]> { return Observable.create((observer: Observer<any>) => { … observer.next(this.episodes); })}

this.episodeService.getEpisodes().subscribe((data) => {…

}

More Architecture

ModelIEpisodeid: numbertitle: stringdescription: stringdateRecorded: stringdateReleased?: stringlocation: stringvideoUrl: stringepisodeNumber: numberguests: string[]links?: ILink[]

ILinkurl: string;title: string;

guest

ComponentsepisodeList.component

episode.component

episode.component

episode.component

episode.component

Routingapp.component

<router-outlet></router-outlet>

…/episodeList…/episodeList/guest/John Smith…/episodeList/location/Chicago, IL

episodeList.component

episode.component

episode.component

episode.component

episode.component

Routingapp.component

<router-outlet></router-outlet>

…/episodeDetails/425

episodeDetails.component

Service

getEpisodes()

episodes: IEpisode[];allEpisodes: IEpisode[];

getEpisodes()

episodeList.component

episode.service

api/episode

Subscribes to

DEMO

top related