with Andrei Antal
slides.com/andreiantal/angular2_voxxed-25/
slides:
Andrei Antal
frontend engineer @ Qualitance
Contact me at:
antal.a.andrei@gmail.com
2009 - Angular project - Misko Hevery, Adam Abrons
2012 - Angular 1.0 release
2013 - React from Facebook
2010 - implemented @Google by Misko Hevery
2014 - Angular 2 - first announcement
2014 - VueJS - Evan You
2015 - Angular 1.4
2016 - Angular 1.5 - 2 february (components)
2016 - Angular 2 - final release - 14 september
2017 - Angular v4 (just Angular) - 23 March
2017 - Angular v5 - 1 November
2016 - Angular 1.6 - 12 december
Features:
Features:
Common problems with Javascript today
class Pizza {
constructor(toppings) {
this.toppings = toppings
}
listToppings() {
toppings.forEach(function(topping) {
console.log(topping.toString();
}
}
}
var pizza = new Pizza();
pizza.listToppings();
// ES5 function
const sum = function(num1, num2) {
return num1 + num2;
};
// ES6 arrow function
const sum = (num1, num2) => { return num1 + num2 };
// ES5 function
const getTempItem = function(id) {
return {
id: id,
name: "Temp"
};
};
// ES6 arrow function
const getTempItem = id => ({ id: id, name: "Temp" });
var firstName = "Andrei",
lastName = "Antal";
// ES5
var fullName = "The full name is: " + firstName + " " + lastName
// ES6 template strings
var fullName = `The full name is: ${firstName} ${lastName}`;
// ES5
function() {
if(true) {
var x = 1;
}
console.log(x) // 1
}
// ES6
function() {
if(true) {
let x = 1;
}
console.log(x) // ReferenceError: x doesn't exist here
}
function() {
const a; // error, need to initialize const
const b = 1;
b = 2; // error cannot reasign
}
const animal = {
name: 'Dog',
sound: 'wof'
};
function makeSound(options) {
options.name = options.name || 'animal';
console.log(`The ${options.animal} goes ${options.sound}`)
}
function makeSound({name = 'animal', sound}) {
console.log(`The ${name} goes ${sound}`)
}
makeSound(animal);
let options = {
repeat: true,
save: false
};
let {repeat, save} = options;
console.log(repeat); // true
console.log(save); // false
let isDone: boolean = false;
let height: number = 6;
let name: string = "bob";
let list: number[] = [1, 2, 3];
let list: Array<number> = [1, 2, 3];
enum Color {Red, Green, Blue};
let c: Color = Color.Green;
let notSure: any = 4;
notSure = "maybe a string instead";
notSure = false; // okay, definitely a boolean
class Person {
name: string;
nickName?: string;
constructor(name: string) {
...
}
}
const p = new Person("Andrei");
interface ClockInterface {
currentTime: Date;
setTime(d: Date);
}
class Clock implements ClockInterface {
currentTime: Date;
setTime(d: Date) {
this.currentTime = d;
}
constructor(h: number, m: number) { }
}
//declare
private _possessions: Array<Thing>;
constructor(){
//assign
this._possessions = new Array<Thing>();
}
@Component({
selector: 'my-app',
styles: ['h1 {color:#545454;}']
template: `
<h1>
Hello from the {{componentName}}.
</h1>
`
})
export class AppComponent {
@Input() componentName = 'AppComponent';
}
.
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
import {AppModule} from './app';
platformBrowserDynamic().bootstrapModule(AppModule)
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
@NgModule({
imports: [ BrowserModule ],
declarations: [ AppComponent ],
bootstrap: [ AppComponent ]
})
export class AppModule { }
// The browser platform without a compiler
import { platformBrowser } from '@angular/platform-browser';
// The app module factory produced by the static offline compiler
import { AppModuleNgFactory } from './app/app.module.ngfactory';
// Launch with the app module factory.
platformBrowser().bootstrapModuleFactory(AppModuleNgFactory);
....
<body>
<my-app><!-- content managed by Angular --></my-app>
....
</body>
....
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { HttpClientModule } from '@angular/common/http';
import { FeatureModule } from '../feature/feature.module';
import { SomeComponent } from './some.component';
import { SomeDirective } from './some.directive';
import { SomePipe } from './some.pipe';
import { SomeService } from './some.service';
@NgModule({
declarations: [SomeComponent, SomeDirective, SomePipe],
imports: [CommonModule, HttpClientModule, FeatureModule]
exports: [SomeComponent],
providers: [ SomeService ],
})
export class SomeModule {}
import { Component } from '@angular/core';
import { SomeService } from './some.service';
@Component({
selector: 'app-component',
template: `
<div class="component">
<span> Hello, {{name}} </span>
<button (click)="handleClick()"> Start </button>
</div>
`,
styles: ['span { color: red }'],
})
export class AppComponent {
@Input() name: string;
@Output() onClick: EventEmitter;
private views:number = 0;
constructor(private someService: SomeService) { }
onClick() {
this.views += 1;
this.onClick.emit(this.views);
}
}
import { Component, OnInit } from '@angular/core';
import { SomeService } from './someService';
@Component({
selector: 'parent-component',
template: `
<div class="parent">
<app-component
[name]="guestName"
(onClick)="handleClick($event)"
/>
</div>
<span class="component">some text</span>
`,
styles: ['span { color: blue }'],
})
export class ParentComponent implements OnInit{
private guestName:string;
constructor() { }
ngOnInit() {
this.guestName = "Andrei Antal";
}
}
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { ParentComponent } from './parent.component';
import { SomeService } from './some.service';
@NgModule({
imports: [ BrowserModule ],
declarations: [
ParentComponent,
AppComponent
],
exports: [ ParentComponent ],
providers: [ SomeService ]
})
export class MyModule { }
import {Component, OnChanges, OnInit, OnDestroy} from 'angular2/core';
@Component()
export class AppComponent implements OnChanges, OnInit, OnDestroy {
/* 1 */ constructor() { }
// called when an input or output binding changes
/* 2 */ ngOnChanges(changes) { }
// after child initialisation
/* 3 */ ngOnInit() { }
// just before is destroyed
/* 4 */ ngOnDestroy() { }
}
import { Component } from '@angular/core';
import { SomeService } from './someService';
@Component({
selector: 'my-component',
template: `
<div>
Hello component
</div>
`,
styles: [`div { color: red }`],
})
export class MyComponent {
@Input() name;
@Output() onClick: EventEmitter;
constructor(private someService: SomeService) {
}
...
}
<rate-button
[talk]="myTalk"
(rate)="handleRate($event)"
></rate-button>
<input [(ngModel)]="todo.text"></input>
<input [ngModel]="todo.text" (ngModelChange)="todo.text=$event">
It's just syntactic sugar for
<div>Rating {{rating}}</div>
<talk-cmp
*ngFor="let t of talks; let i=index"
[talk]="t"
[index]="i"
></talk-cmp>
<div [textContent]="interpolate(['Rating'], [rating])"></div>
It's just syntactic sugar for
<confirmation-dialog #dialog></confirmation-dialog>
<button (click)="dialog.open()">Open</button>
Syntax | Binding type |
---|---|
<h1>{{title}}</h1> | Interpolation |
<img [alt]="Some image"> | Property |
<li [class.active]="isActive"></li> | Class |
<div [style.width.px]="mySize"> | Style |
<button (click)="onClick($event)"> | Event |
<input [(ngModel)]="data.value"> | Two-way |
import { Injectable } from '@angular/core';
@Injectable()
export class ExampleService {
someMethod() {
return 'Hey!';
}
}
Creating providers
import { FormsModule } from '@angular/forms';
import { HttpClientModule } from '@angular/common/http';
import { ExampleService } from './example.service';
@NgModule({
imports: [ BrowserModule, FormsModule, HttpClientModule ],
declarations: [ App ],
providers: [ ExampleService ],
bootstrap: [ App ]
})
export class AppModule {}
Registering providers
import { Component } from '@angular/core';
import { ExampleService } from './example.service';
@Component({
selector: 'my-app',
template: '<h1>{{ title }}</h1>',
providers: [ExampleService]
})
export class AppComponent {
title: string;
constructor(private _exampleService: ExampleService) { }
ngOnInit() {
this.title = this._exampleService.someMethod();
}
}
Injecting dependencies
Using Data services
The HTTP Module
import { FormsModule } from '@angular/forms';
import { HttpClientModule } from '@angular/common/http';
import { ExampleService } from './example.service';
@NgModule({
imports: [ BrowserModule, FormsModule, HttpClientModule ],
declarations: [ App ],
providers: [ ExampleService ],
bootstrap: [ App ]
})
export class AppModule {}
// src/users.service.ts
import { Injectable } from '@angular/core';
import { HttpClientModule } from '@angular/common/http';
@Injectable()
export class UsersService {
constructor(private http: HttpClientModule) { }
get() {
return this.http.get('/assets/users.json')
}
}
import { Component } from '@angular/core';
import { UsersService } from './users.service';
@Component({
selector: 'users',
template: `<h1>Users</h1>
<tr *ngFor="let user of userslist">
<td>{{user.username}}</td>
</tr>`
})
export class Users {
private userslist;
constructor(private users: UsersService) { }
ngOnInit() {
users.get().subscribe( userResult => this.usersList = userResult );
}
}
import { Component } from '@angular/core';
import { UsersService } from './users.service';
@Component({
selector: 'users',
template: `<h1>Users</h1>
<tr *ngFor="let user of usersList | async">
<td>{{user.username}}</td>
</tr>`
})
export class Users {
private userslist;
constructor(private users: UsersService) {}
ngOnInit() {
this.usersList = this.users.get();
}
}
Streams
myObservable.subscribe(successFn, errorFn)
myPromise.then(successFn, errorFn)
myObservable.subscribe(successFn, errorFn, completeFn)
myPromise.then(successFn, errorFn)
import { Routes, RouterModule } from '@angular/router';
import { Home } from './home.component';
import { About } from './about.component';
import { NotFound } from './notfound.component';
const appRoutes: Routes = [
{ path: '', redirectTo: 'home', pathMatch: 'full' },
{ path: 'home', component: Home },
{ path: 'about', component: About },
{ path: '**', component: NotFound }, //always last
];
export const AppRouting = RouterModule.forRoot(appRoutes, { useHash: true });
import { FormsModule } from '@angular/forms';
import { HttpClientModule } from '@angular/common/http';
import { ExampleService } from './example.service';
import { AppRouting } deom './app.routing';
@NgModule({
imports: [
BrowserModule,
FormsModule,
HttpClientModule,
AppRouting
],
declarations: [ App ],
providers: [ ExampleService ],
bootstrap: [ App ]
})
export class AppModule {}
import { Routes, RouterModule } from '@angular/router';
import { Home } from './home.component';
import { About } from './about.component';
import { NotFound } from './notfound.component';
const appRoutes: Routes = [
{ path: '', redirectTo: 'home', pathMatch: 'full' },
{ path: 'home', component: Home },
{ path: 'about', component: About },
{
path: 'details',
loadChildren: 'app/details.module#DetailsModule',
},
{ path: '**', component: NotFound }, //always last
];
export const AppRouting = RouterModule.forRoot(appRoutes);
import { RouterModule } from '@angular/router';
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { DetailsComponent } from './details.component';
@NgModule({
imports: [
CommonModule,
RouterModule.forChild([{
path: '',
component: DetailsComponent,
},
{
path: ':id',
component: DetailsComponent,
}]),
],
declarations: [ DetailsComponent ],
exports: [ RouterModule ]
})
export class DetailsModule { }
Template driven forms
Model driven / Reactive
@Component({
template: `
<form #f="ngForm" (submit)="onSubmit(f.form.value)">
<input type="email"
[(ngModel)]="model.email"
name="email"
#email="ngModel"
required>
<div [hidden]="email.valid">Email is required</div>
<button type="submit" [disabled]="!f.form.valid">Submit</button>
</form>`
})
export class Contact {
model = {};
onSubmit(value) {
console.log(`Submitted: ${JSON.stringify(value)}`);
}
}
// installing
$ npm install -g @angular/cli
// scaffold the project
$ ng new PROJECT_NAME
$ cd PROJECT_NAME
// start the project
$ ng serve
// generate components
$ ng g component my-new-component