"Once you stop learning, you start dying"

- Albert Einstein

RACHEL HEIMBACH

Developer

rheimbach@quintor.nl

@Rach_Nerd

HENK BAKKER

Developer

hbakker@quintor.nl

@spike1292

XML

Angular 2

  • Big community
  • Popular framework
  • Scales well
  • Code share

NativeScript

  • iOS + Android app
  • Native performance
  • No webview
  • Angular 2 integration

XML

JSON

Application level

Essent modules

API Gateway

Code sharing

 

  • Component-based
  • Dependency injection
  • Modules (Http, Forms, ...)
  • Platform independent

This is not PhoneGap, Cordova or Ionic

  • Real Native Components
  • No DOM to manipulate
  • Not HTML elements styled like native components

Use lots of prebuilt code

Native Layout Containers

Absolute

Dock

Grid

Stack

Wrap

Like '<div>' - more concise though

<Page xmlns="http://schemas.nativescript.org/tns.xsd">

  <StackLayout class="p-20">
    <Label text="Tap the button" class="h1 text-center"/>
    <Button text="TAP" tap="{{ onTap }}" class="btn btn-primary"/>
  </StackLayout>

</Page>

// DOM comparison...

<html>
<body>

  <div class="p-20">
    <h1 class="h1 text-center">Tap the button</h1>
    <button type="button" class="btn btn-primary" 
        (tap)="onTap()">TAP</button>
  </div>

</body>
</html>
            

VM

const switch = new Switch();

Nativescript modules

Nativescript runtime

Switch module

NativeScript Modules

State management!?

?

RxJS

"...is a set of libraries to compose asynchronous and event-based programs using observable collections and Array style composition in JavaScript" - RxJS

Observable

"The Observer and Observable interfaces provide a generalized mechanism for push-based notification, also known as the observer design pattern." -RxJS

const observable$ = Observable.of('foo');

observable$
    .subscribe(
        value => console.log(value),
        error => console.error(error),
        () => console.log('Completed')
    );
// LOG: foo
// LOG: Completed

observable$
    .map(text => text + ' bar')
    .subscribe(
        value => console.log(value),
        error => console.error(error),
        () => console.log('Completed')
    );
// LOG: foo bar
// LOG: Completed

Subject

"An RxJS Subject is a special type of Observable that allows values to be multicasted to many Observers" - RxJs

const subject = new Subject();

subject
    .subscribe(
        value => console.log(value),
        error => console.error(error),
        () => console.log('Completed')
    );
subject.next('foo'); // LOG: foo
subject.next('bar'); // LOG: bar
subject.complete(); // LOG: Completed
subject.next('foo'); 
const subject = new Subject();
const observable$ = subject.asObservable();

observable$
    .subscribe(
        value => console.log(value),
        error => console.error(error),
        () => console.log('Completed')
    );


subject.next('foo'); // LOG: foo
subject.next('bar'); // LOG: bar
observable$.next('foo'); // Error
@Injectable()
export class BudgetBillService {
    amount$: Observable<number>;
    private budgetBillStateSubject: Subject<BudgetBillState>;

    constructor(private http: Http) {
        this.budgetBillStateSubject = new Subject<BudgetBillState>();
        this.amount$ = this.budgetBillStateSubject.asObservable()
            .map((bbState: BudgetBillState) => bbState.amount);
    }

    get(): void {
        this.http.get('assets/bbs.json')
            .map((res: Response) => res.json())
            .subscribe(
                (bbState: BudgetBillState) => 
                    this.budgetBillStateSubject.next(bbState),
                (error: Response) => console.error(error),
                () => console.log('Completed')
            );
    }
}

Streams
are
awesome!

Tips state management

  • Keep state in streams
  • Expose state as an observable
  • Manipulate state by executing actions that push data through streams
  • Never manually call error/complete on a stream you do not wish to close

Hot/Cold Observable

Hot

Cold

@Injectable()
export class TodosService {
    todos$: Observable<Todo[]>;
    private todosSubject: Subject<Todo[]>;

    constructor(private http: Http) {
        this.todosSubject = new Subject();
        this.todos$ = this.todosSubject.asObservable();
    }

    get(): void {
        this.http.get('assets/todos.json')
            .map((res: Response) => res.json())
            .subscribe(
                (todos: Todo[]) => this.todosSubject.next(todos),
                (error: Response) => console.error(error),
                () => console.log('Completed')
            );
    }
}

Hot

@Component({
    selector: 'q-todos',
    templateUrl: 'todos.component.html',
    styleUrls: ['todos.component.css']
})
export class TodosComponent implements OnInit {
    todos: Todo[] = [];

    constructor(private todosService: TodosService) {
    }

    ngOnInit() {
        this.todosService.todos$
            .subscribe(
                (todos: Todo[]) => this.todos = todos
            );
        this.todosService.get();
    }
}

Subscription

"A Subscription is an object that represents a disposable resource, usually the execution of an Observable." - RxJS

const subject = new Subject();

const observable$ = subject.asObservable();

const subscription = observable$
                         .subscribe(value => 
                             console.log(value)
                         );
subject.next('foo'); // LOG: foo
subscription.unsubscribe();
subject.next('bar'); 
@Component({
    selector: 'q-todos',
    templateUrl: 'todos.component.html',
    styleUrls: ['todos.component.css']
})
export class TodosComponent implements OnInit, OnDestroy {
    todos: Todo[] = [];
    private ngUnsubscribe = new Subject();

    constructor(private todosService: TodosService) {
    }

    ngOnInit() {
        this.todosService.todos$
            .takeUntil(this.ngUnsubscribe)
            .subscribe(
                (todos: Todo[]) => this.todos = todos
            );
        this.todosService.get();
    }

    ngOnDestroy() {
        this.ngUnsubscribe.next();
        this.ngUnsubscribe.complete();
    }
}
@Component({
    selector: 'q-todos',
    templateUrl: 'todos.component.html',
    styleUrls: ['todos.component.css']
})
export class TodosComponent implements OnInit {
    todos$: Observable<Todo[]>;

    constructor(private todosService: TodosService) {
    }

    ngOnInit() {
        this.todos$ = this.todosService.todos$
        this.todosService.get();
    }
}
<div *ngIf="todos$ | async as todos; else loading">
    <div *ngFor="let todo of todos">
        {{ todo.content }}
    </div>
</div>
<ng-template #loading>Loading...</ng-template>

Docs: https://angular.io/docs/ts/latest/api/common/index/NgIf-directive.html

Tips observables

  • Identify hot observables
  • Use async pipe to clean up hot subscriptions
  • Unsubscribe remaining hot subscriptions onDestroy()
  • Make use of operators like .take(1) to convert a hot streams to cold streams

Demo

Time

Nativescript Angular Case study

By Henk

Nativescript Angular Case study

  • 379