Custom widgets for Angular 2?

Piece of cake!


Pawel Kozlowski (@pkozlowski_os)

Widgets

https://ng-bootstrap.github.io

Native

Testability

Next level

(Un)clear semantics

Bindings

<div uib-tooltip="exp">
<div uib-tooltip="{{exp}}">
<div uib-tooltip="Static text">

Mixed case names

<div uib-tooltip="...">
<div uibTooltip="...">

Clear semantics

<div [ngbTooltip]="exp">
<div ngbTooltip="Static text">

Inert <template>

<uib-tabset>
    <uib-tab title="Simple">Some simple text</uib-tab>
    <uib-tab title="Expensive stuff">
      <very-expensive-stuff></very-expensive-stuff>
    </uib-tab>
</uib-tabset>

Inert <template>

<ngb-tabset>
  <ngb-tab title="Simple">
    <template ngbTabContent>Some simple text</template>
  </ngb-tab>
  <ngb-tab title="Expensive stuff">
    <template ngbTabContent>
      <very-expensive-stuff></<very-expensive-stuff>
    </template>
  </ngb-tab>
</ngb-tabset>

Reactive parenting

@Component({
  template: `
    <ul [class]="'nav nav-' + type" role="tablist">
      <li class="nav-item" *ngFor="let tab of tabs">...</li>
    </ul>
    <div class="tab-content">
      <template ngFor let-tab [ngForOf]="tabs">
        ...
      </template>
    </div>`
})
export class NgbTabset implements AfterContentChecked {

  @ContentChildren(NgbTab) tabs: QueryList<NgbTab>;
  ...
}

Exported instances

<button ngbTooltip="Hint!">
  I've got a tip!
</button>

Exported instances

code

@Directive({selector: '[ngbTooltip]', exportAs: 'ngbTooltip'})
export class NgbTooltip implements OnInit, OnDestroy

  toggle(): void {
    ...
  }
}

usage

<button ngbTooltip="Hint!" #t="ngbTooltip" (click)="t.toggle()">
  I've got a tip!
</button>

CSS encapsulation

CSS encapsulation

@Component({
  selector: '[ngbDatepickerNavigation]',
  styles: [`
    td {
      text-align: center;
      padding-bottom: 0.25rem;
    }
  `],
  ...
 })
 export class NgbDatepickerNavigation {
  ..
 }

RxJS

RxJS-powered typeahead

<input [(ngModel)]="state" [ngbTypeahead]="findState" />
 findState = (userInput$: Observable<string>) => userInput$
  .filter(term => term.length > 2)
  .debounceTime(200)
  .distinctUntilChanged()
  .map(term => new RegExp(term, 'gi').test(state));

ngZone.onStable

ngZone.onStable.subscribe(() => {
  if (this._isPopoverOpen()) {
    positionElements(
        this._elementRef.nativeElement,
        this._windowRef.location.nativeElement,
        this.placement);
  }
});

Sweet!

(keyup.arrowLeft)="previousSlide()"
(document:click)="closeOthers($vent)"
[class.active]="isOpen(panel.id)"

Does it all matter?

Tabset (300 vs. 150 LOC)

Typeahead (20 vs. 8 items on the API surface)

Performance

@Component({
  selector: 'ngb-pagination',
  changeDetection: ChangeDetectionStrategy.OnPush,
  template: `...`
})
export class NgbPagination implements OnChanges {
  ...
}

Server-side rendering

Animations

UI toolkit

PresentationRef

Bon Appétit!