building a tv show with angular, bootstrap, and web services
Post on 13-Jan-2017
196 Views
Preview:
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
Links• channel9.msdn.com/blogs/technology-and-friends • angular.io/ • github.com/DavidGiard/dgtv • tinyurl.com/dgtvslides
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
Links• channel9.msdn.com/blogs/technology-and-friends • angular.io/ • github.com/DavidGiard/dgtv • tinyurl.com/dgtvslides
top related