Components

Data Flow: Passing Static Strings To Components

<my-component someAttr="Hello World"></my-component>
@Input() someAttr: string;

Data Flow: Passing Dynamic Values To Components

<my-component [someAttr]="someVar"></my-component>
@Input() someAttr: string;
_someAttr: string;
@Input() set someAttr(a: string) {
    console.debug("Caller changed value for someAttr: ", a);
    this._someAttr = string;
}

Data Flow: Responding to Component Events

<my-component (someAttr)="someHandler($event, ...)"></my-component>
<my-component (someAttr)="myVar=$event"></my-component>
@Output someAttr: EventEmitter<string>;

this.someAttr = new EventEmitter<string>();

this.someAttr.emit('Hello World'); // "Hello World" == $event
myComponentRef.someAttr.subscribe(s => this.myVar = s);

Data Flow: Passing Dynamic Values To/From Components

This is most like AngularJS ng-model="someVar";

<my-component [(ngModel)]="someVar"></my-component>
Note
custom components typically don’t implement [(ngModel)] but instead use a combination of input and output channels.

Data Flow: Direct Communication

<my-component #myComponent></my-component>
@ViewChild('myComponent') myCompRef: MyComponent;

this.myCompRef.someAttr = this.whatever;
this.myCompRef.someFunction();
Note
this.myCompRef will be NULL when *ngIf prevents #myComponent from rendering!

Templates / Syntax

<div *ngFor="let color of colors">
  <div *ngIf="color == 'blue'">
    <span i18n>I like {{blue}}</span>
  </div>
</div>

<ng-template>
    <!-- Pre-compiled template executed on demand -->
</ng-template>

<ng-container>
    <!-- No-Op container, good for combining with ngFor/ngIf -->
</ng-container>

Template Variables

<!-- content I want to render -->
<ng-template #myTemplate let-city="adCity" let-state="adState">
  <marquee i18n>
    Welcome to Mattress City of {{city}}, {{state}}!
  </marquee>
</ng-template>

<ad-component [adTemplate]="myTemplate">
</ad-component>
@Input() adTemplate: TemplateRef<any>;
<ng-container *ngTemplateOutlet="adTemplate; context: someObject">
</ng-container>

Lifecycle hooks

Canned event bindings, neat!

<input type="text" (keyup.enter)="doStuffOnEnter()"/>

Modules

Modules serve 2 main functions:

Modules

@NgModule({
  declarations: [
    /*
    List of components declared by this module.  Every component used
    must be declared exactly once throughout the entire application
    including lazy-loaded modules!
    */
  ],
  imports: [
    /*
    List of imported modules.  These modules may be needed by the
    current module or imported so they can be re-exported (below).
    */
  ],
  exports: [
    /*
    List of components and modules made implicitly
    available to any module that imports this module.
    */
  ],
  providers: [
    /*
    List of services available to this module and any
    module that imports this module.
    NOTE: @Injectable({providedIn: 'root'}) are globally provided
    and share a single execution context.
    */
  ]
})

Routing: Parameters

const routes: Routes = [
  { path: 'record/:id',
    component: RecordComponent
  }, {
    path: 'record/:id/:tab',
    component: RecordComponent
  }
];

Routing: Parameters

constructor(private route: ActivatedRoute) {}

ngOnInit() {
    this.route.paramMap.subscribe((params: ParamMap) => {
        this.recordId = +params.get('id');  // '+' coerce number
        this.recordTab = params.get('tab') || 'copy_table';
        this.loadRecord();
    });
}

Routing: Resolvers / Lazy Loading

staff.module.ts

const routes: Routes = [{
  path: '',
  component: StaffComponent,
  resolve: {staffResolver : StaffResolver},
  children: [{
    path: 'catalog',
    loadChildren : '@eg/staff/catalog/catalog.module#CatalogModule'
  }]
}];

Navigate to /staff/catalog

Misc.

Observables

import {Observable} from 'rxjs/Observable';
import {map} from 'rxjs/operators/map';

getThings(): Observable<any> {
    return this.net.request(service, method, arg)
    .pipe(
        map(oneValue => {
            oneValue.bar = 'baz';
            return oneValue;
        })
    );
}
thing.getThings().subscribe(oneValue => console.log(oneValue.bar));

Gotchas: Error handling

Gotchas: Runtime Deps vs Dev Deps

npm install --save-dev typescript

Compiling

My Dev Setup

ln -s /home/berick/code/Evergreen/Open-ILS/web/eg2/en-US \
    /openils/var/web/eg2/en-US
ng build --watch
ng-lint
ng build --prod # then test

Big Questions