@laco2net
2017-10-10 ng-japan Meetup
Why is Angular popular?
@Component({
selector: "app-profile",
template: "<p>Name: {{ name }}</p>"
})
class ProfileComponent {
@Input() name: string;
}
<div>
<app-profile name="laco"></app-profile>
</div>
Data-Binding: [prop]
@Component({
template: `
<input [value]="name">
<div [attr.role]="role"></div>
<div [class.large]="isLarge"></div>
<div [style.width.px]="mySize"></div>
`
})
class MyComponent {
name = "laco";
role = "main"
isLarge = true;
mySize = 16;
}
Event Handling: (event)
@Component({
template: `
<button (click)="onClick($event)">
`
})
class MyComponent {
onClick(e: MouseEvent) {
}
}
# Install Angular CLI
> npm install -g @angular/cli
# Create new app
> ng new hello-angular
# Test
> ng test
# Build
> ng build --prod
# Debug
> ng serve
Easy to develop Angular apps
@angular/core
@angular/common
@angular/forms
@angular/http
@angular/router
@angular/material
@angular/platform-server
@angular/service-worker
@angular/language-service
...
Static Type
Decorators
Type-base Dependency Injection
Language Services
Types in the template
Angular x.y.z
x: major
Update can contain breaking changes
y: minor
Update cannot breaking changes
z: patch
Only bug fix
Every weak: patch update
Every month: minor update
Every 6 months: major update
[@anim.disabled]
Disable Animations by data-binding
Negative Query Limit
Count from tail
@Component({
animations: [
trigger("counter", [
transition(':increment', [ /*...*/ ]),
transition(':decrement', [ /*...*/ ]),
])
],
template: `
<span [@counter]="count">
`
})
class MyComponent() {
count = 1;
}
@Component({
animations: [
trigger("anim", [ /* ... */])
],
template: `
<div [@anim]="prop" [@anim.disabled]="animationDisabled">
`
})
class MyComponent() {
prop = '';
animationDisabled = false;
}
trigger("anim", [
transition(":enter", [
query(
".item",
[ /** ... **/ ],
{ limit: -5 }
)
])
])
router.events
// Event = RouteEvent | RouterEvent
.filter(e => e instanceof RouteEvent)
.subscribe(e => {
if (e instanceof ChildActivationStart) {
spinner.start();
} else if (e instanceof ChildActivationEnd) {
spinner.end()
}
});
router.events
// Event = RouteEvent | RouterEvent
.filter(e => e instanceof RouteEvent)
.subscribe(e => {
if (e instanceof ActivationStart) {
spinner.start();
} else if (e instanceof ActivationEnd) {
spinner.end()
}
});
<form [ngFormOptions]="{updateOn: 'change'}">
<input name="foo"
[(ngModel)]="foo"
[ngModelOptions]="{updateOn: 'blur'}">
<input name="bar"
[(ngModel)]="bar"
[ngModelOptions]="{updateOn: 'submit'}">
</form>
@Directive({
selector: 'sushi-maguro',
exportAs: 'maguro, tuna'
})
export class LacoDirective {}
`
<sushi-maguro' #maguro="maguro" #tuna="tuna">
<!-- maguro === tuna -->
</sushi-maguro'>
`
platformBrowserDynamic()
.bootstrapModule(AppModule, {
ngZone: 'zone.js' // or 'noop' or Custom NgZone
})
http.get("/api", {
headers: {
"X-MY-HEADER": "header"
},
params: {
"foo": "bar"
},
})
const COUNTER_KEY = makeStateKey<number>('counter');
@Component({...})
export class TransferStateComponent {
counter = 0;
constructor(@Inject(PLATFORM_ID) private platformId: {},
private transferState: TransferState) {}
ngOnInit() {
if (isPlatformServer(this.platformId)) {
this.counter = 5;
this.transferState.set(COUNTER_KEY, 50);
} else {
this.counter = this.transferState.get(COUNTER_KEY, 0);
}
}
@NgModule({
bootstrap: [MyServerApp],
declarations: [MyServerApp],
imports: [
BrowserModule.withServerTransition({appId: 'render-hook'}),
ServerModule
],
providers: [
{
provide: BEFORE_APP_SERIALIZED,
useFactory: getTitleRenderHook,
multi: true, deps: [DOCUMENT]},
]
})
class RenderHookModule {}
@angular/http
Core
Drop <template> Support
Drop OpaqueToken
Require TypeScript >=2.4.x
Common Pipes using Intl API
Drop dependency on Intl
import { registerLocaleData } from '@angular/common';
import localeJa from '@angular/common/locales/ja';
registerLocaleData(localeJa);
import {
CommonModule,
DeprecatedI18NPipesModule
} from '@angular/common';
@NgModule({
imports: [
CommonMudule,
DeprecatedI18NPipesModule,
]
})
export class AppModule {}
md* => mat*
use angular-material-prefix-updater w/ beta.11
$ mat-switcher --help
Drop all-in-one MaterialModule
MatInputModule
<md-input-container> => <mat-form-field>
All* Components use OnPush
--build-optimizer (v1.3) => default in v1.5
Optimize AoT-generated code
platform-server support (v1.3)
Build app for Node.js
Custom Template (v1.4)
Schematics: Scaffolding Tool by Angular Team
Default templates: @schematics/angular
--collection option to choose schematics package
ES2015 Support (v1.5)
tsconfig.compilerOptions.target
Read angular.io
Official documentation
Use Angular CLI
Follow the Best Practice
Angular is a Platform for Developer Experience
v5 Updates
Some new features and removal
Breaking changes on I18N pipes
How to learn Angular
Read angular.io
Use Angular CLI
Follow the Best Practice
Keep an eye on changes