Slide 1

Slide 1 text

Angular ONE with ng-metadata

Slide 2

Slide 2 text

Strings I hate

Slide 3

Slide 3 text

Angular I like

Slide 4

Slide 4 text

angular .module('app', ['ui.router','ocLazyLoad']) .service('logger', ['$log', function LoggerService($log) {} ]) .filter('wat', function watFilter(){}) .directive('uhOh', function uhOhDirective(){ return { bindToController: { one: '<', two: '@', onThree: '&' } controller: class UhOhCtrl{ static $inject = ['$http']; constructor($http){ this.$http = $http } } } });

Slide 5

Slide 5 text

Strings

Slide 6

Slide 6 text

Martin Hochel @martin_hotell github.com/Hotell software engineer @embeditCZ typeof whoAmI

Slide 7

Slide 7 text

#devsUnited ngParty Prague, Czech Republic meetup.com/ngParty slack.ngparty.cz @ngPartyCZ

Slide 8

Slide 8 text

So what about those strings ?

Slide 9

Slide 9 text

No content

Slide 10

Slide 10 text

@Component({ selector: 'my-uh-oh', }) class UhOhComponent { @Input() one; @Input() two; @Output() three = new EventEmitter(); } @NgModule({ declarations: [UhOhComponent] providers: [LoggerService] }) class AppModule{} Angular 2

Slide 11

Slide 11 text

Talk about Angular 1 ? What year is it ?

Slide 12

Slide 12 text

Just use Angular 2 dude!

Slide 13

Slide 13 text

No content

Slide 14

Slide 14 text

There are hundreds ng 1 apps out there

Slide 15

Slide 15 text

Go Hybrid! via ngUpgrade

Slide 16

Slide 16 text

Sure

Slide 17

Slide 17 text

Introducing

Slide 18

Slide 18 text

My codebase

todos

Mark all as complete
  • {{todo.title}}
{{remainingCount}}

Slide 19

Slide 19 text

Refactoring

Slide 20

Slide 20 text

component driven architecture

Slide 21

Slide 21 text

Smart / Dumb components http://teropa.info/blog/2015/10/18/refactoring-angular-apps-to-components.html

Slide 22

Slide 22 text

ES 2015 http://ngmigrate.telerik.com

Slide 23

Slide 23 text

Refactored! export const TodoFormComponent = { bindings: { todo: '<', onAddTodo: '&' }, templateUrl, controller: class TodoFormComponent { static $inject = [‘eventEmitter’] constructor(EventEmitter) { this.EventEmitter = EventEmitter; } $onChanges(changes) { if (changes.todo) { this.todo = Object.assign({}, this.todo); } } onSubmit() { // without EventEmitter wrapper this.onAddTodo({ $event: { todo: this.todo } }); } } };

Slide 24

Slide 24 text

Strings anyone?

Slide 25

Slide 25 text

Now Go Hybrid!

Slide 26

Slide 26 text

Refactoring Refactoring

Slide 27

Slide 27 text

Hybrid app - downgraded ng2 component import { HeroDetailComponent } from './hero-detail.component'; import { downgradeComponent } from '@angular/upgrade/static'; angular.module('heroApp', []) .controller('MainController', MainController) .directive('heroDetail', downgradeComponent({ component: HeroDetailComponent, inputs: ['hero'], outputs: ['deleted'] }) as angular.IDirectiveFactory);

Slide 28

Slide 28 text

Hybrid app - upgraded ng1 service to ng2 @NgModule({ imports: [ BrowserModule, UpgradeModule ], providers: [{ provide: 'heroes', useFactory: (i: any) => i.get('heroes'), deps: ['$injector'] }], /* . . . */ }) export class AppModule { ngDoBootstrap() {} } @Component({ selector: 'hero-detail', template: `

{{hero.id}}: {{hero.name}}

` }) export class HeroDetailComponent { hero: Hero; constructor(@Inject('heroes') heroes) { this.hero = heroes.get()[0]; } }

Slide 29

Slide 29 text

but...

Slide 30

Slide 30 text

Did you notice? angular.module('heroApp', []) .controller('MainController', MainController) .directive('heroDetail', downgradeComponent({ component: HeroDetailComponent, inputs: ['hero'], outputs: ['deleted'] }) as angular.IDirectiveFactory); @NgModule({ providers: [{ provide: 'heroes', useFactory: (i: any) => i.get('heroes'), deps: ['$injector'] }], /* . . . */ }) export class AppModule { ngDoBootstrap() {} } @Component({...}) export class HeroDetailComponent { hero: Hero; constructor(@Inject('heroes') heroes) { this.hero = heroes.get()[0]; } }

Slide 31

Slide 31 text

Strings anyone?

Slide 32

Slide 32 text

So this talk is about strings or wot?

Slide 33

Slide 33 text

Angular 1 With ng-metadata

Slide 34

Slide 34 text

Angular 2 decorators and utils for Angular 1.x

Slide 35

Slide 35 text

ngMetadata Angular 1

Slide 36

Slide 36 text

No content

Slide 37

Slide 37 text

No content

Slide 38

Slide 38 text

Basic building blocks

Slide 39

Slide 39 text

@Component import { Component, EventEmitter, Input, Output } from 'ng-metadata/core'; import { Hero } from '../hero'; @Component({ selector: 'hero-detail', template: `

{{$ctrl.hero.name}} details!

id: {{$ctrl.hero.id}}
Delete ` }) export class HeroDetailComponent { @Input() hero: Hero; @Output() deleted = new EventEmitter(); onDelete() { this.deleted.emit(this.hero); } }

Slide 40

Slide 40 text

@Directive import { Directive, HostListener, Input, Inject, Output, EventEmitter } from 'ng-metadata/core'; @Directive({ selector: '[myHighlight]' }) export class HighlightDirective { @Input() set defaultColor(colorName: string){ this._defaultColor = colorName || this._defaultColor; } @Input('color') highlightColor: string; @Output() onColorClick = new EventEmitter(); @HostListener('mouseenter') onMouseEnter() { this.highlight(this.highlightColor || this._defaultColor); } @HostListener('mouseleave') onMouseLeave() { this.highlight(null); } }

Slide 41

Slide 41 text

@Injectable import {Injectable} from 'ng-metadata/core' import { Hero } from './hero'; @Injectable() export class HeroesService { get() { return [ new Hero(1, 'Windstorm'), new Hero(2, 'Spiderman'), ]; } } import { Component,OnInit,HostBinding,Inject } from 'ng-metadata/core' @Component({ selector: 'my-heroes', template: `...` }) export class HeroesComponent implements OnInit { @HostBinding('attr.role') role = 'widget'; constructor( private heroesSvc: HeroesService, @Inject('$log') private $log: ng.ILogService ) {} ngOnInit(){ this.$log.log( this.heroesSvc.get() );

Slide 42

Slide 42 text

@Pipe import { Pipe } from 'ng-metadata/core'; @Pipe( { name:'uppercase' } ) class UppercasePipe{ transform( input: string):string{ return input.toUpperCase(); } }

Slide 43

Slide 43 text

Hierarchical/Local DI @Host @Self @SkipSelf @Optional

Slide 44

Slide 44 text

Querying for Children @ViewChild @ViewChildren @ContentChild @ContentChildren

Slide 45

Slide 45 text

Templates

Slide 46

Slide 46 text

Slide 47

Slide 47 text

Slide 48

Slide 48 text

registering to angular container

Slide 49

Slide 49 text

provide()

Slide 50

Slide 50 text

provide import {provide} from 'ng-metadata/core'; export const MyApp = angular.module( 'myApp', [] ) .directive( ...provide( MyCmp ) ) .directive( ...provide( MyAttr ) ) .filter( ...provide( UppercasePipe ) ) .service( ...provide( Greeter ) );

Slide 51

Slide 51 text

@NgModule

Slide 52

Slide 52 text

@NgModule import { NgModule } from 'ng-metadata/core'; @NgModule({ declarations: [ MyPipe, MyComponent ], providers: [ MyService ], imports: [ MyCommonModule, ThirdPartyModule, ‘ui.router’ ] }) export class MyModule {}

Slide 53

Slide 53 text

bootstrap

Slide 54

Slide 54 text

bootstrap // main.ts import { platformBrowserDynamic } from 'ng-metadata/platform-browser-dynamic'; import { AppModule } from './app.module'; platformBrowserDynamic().bootstrapModule( AppModule );

Slide 55

Slide 55 text

Other super powers

Slide 56

Slide 56 text

Async pipe

Slide 57

Slide 57 text

Title service

Slide 58

Slide 58 text

ChangeDetectorRef

Slide 59

Slide 59 text

ChangeDetectionStrategy.OnPush Within @Component

Slide 60

Slide 60 text

Testing Utils

Slide 61

Slide 61 text

What about Hybrid?

Slide 62

Slide 62 text

Use ngUpgrade with ngMetadata

Slide 63

Slide 63 text

ngMetadata entity Angular 2 entity Upgrade (search and replace) Downgrade (via ngUpgrade)

Slide 64

Slide 64 text

ngMetadata @Component import { Component, EventEmitter, Input, Output } from 'ng-metadata/core'; import { Hero } from '../hero'; @Component({ selector: 'hero-detail', template: `

{{$ctrl.hero.name}} details!

id: {{$ctrl.hero.id}}
Delete ` }) export class HeroDetailComponent { @Input() hero: Hero; @Output() deleted = new EventEmitter(); onDelete() { this.deleted.emit(this.hero); } }

Slide 65

Slide 65 text

Upgrade to ng2 @Component import { Component, EventEmitter, Input, Output } from '@angular/core'; import { Hero } from '../hero'; @Component({ selector: 'hero-detail', template: `

{{hero.name}} details!

id: {{hero.id}}
Delete ` }) export class HeroDetailComponent { @Input() hero: Hero; @Output() deleted = new EventEmitter(); onDelete() { this.deleted.emit(this.hero); } } ‘ng-metadata/core’ => ‘@angular/core’ ng-* => (*) or [ * ] $ctrl.* => *

Slide 66

Slide 66 text

ngMetadata @NgModule import { NgModule } from 'ng-metadata/core'; import { HeroDetailComponent } from './hero-detail.component'; @NgModule({ declarations:[ HeroDetailComponent ] }) export class AppModule {};

Slide 67

Slide 67 text

Downgrade so it works with ng1 @Component import { downgradeComponent } from '@angular/upgrade/static/'; import { provideNg2Component } from 'ng-metadata/upgrade'; import { NgModule } from 'ng-metadata/core'; import { HeroDetailComponent } from './hero-detail.component'; @NgModule({ declarations:[ provideNg2Component({ component: HeroDetailComponent, downgradeFn:downgradeComponent }) ] }) export class AppModule {};

Slide 68

Slide 68 text

Strings!

Slide 69

Slide 69 text

And much more!

Slide 70

Slide 70 text

Payload: ~22kb minified+gzip

Slide 71

Slide 71 text

Angular 2 ecosystem with ng1 (ngMetadata) Angular 2 style guides RxJs Codelyzer ngRedux

Slide 72

Slide 72 text

Play with it/use it right now! Plunker Starter Kit

Slide 73

Slide 73 text

Demo ?

Slide 74

Slide 74 text

https://github.com/ngParty/ng-metadata

Slide 75

Slide 75 text

ThankZ ! https://github.com/ngParty/ng-metadata