Slide a View in From Off Screen: NativeScript-Angular

Keeping up with the NativeScript blog, I came across the post “NativeScript Angular — Performance Tips & Tricks.” In the post they discuss optimizing views.

I have used Angular (meaning Angular2, not AngularJS) for some time, but wasn’t really familiar with the concept of attribute directives and selectors. I decided, since it is more preformant on mobile to modify a view in the layout with an attribute directive instead of nesting a component one inside of another GridLayout or StackLayout so I could position it correctly, I’d learn how it works.

A specifically difficult case for me to figure out was: when applying an attribute directive to a view, how to access that directive’s methods to allow me to leverage the functionality of that directive for the implementing view. I tried a lot of searches involving “nativescript angular2 access methods from directive.” It didn’t get me anywhere. After figuring out where the line was between NativeScript and Angular, I finally found what I was looking for.

Using the example of a custom view that slides in from off the bottom of the screen, here is what I found:

snackbar.directive.ts

import { Directive, ElementRef, EventEmitter, Output } from '@angular/core';
import { screen, ScreenMetrics } from 'platform';
const screenScale: number = screen.mainScreen.scale;
const offScreenMargin: number = screen.mainScreen.heightDIPs * -1;
@Directive({
selector: '[snackbar]'
})
export class SnackbarDirective {
    // Let an implementor know when the view has left the screen
@Output() private dismissed: EventEmitter<boolean> = new EventEmitter<boolean>(false);
    private element: ElementRef;
    constructor(el: ElementRef) {
this.element = el;
this.element.nativeElement.marginBottom = offScreenMargin;
}
    public show(): void {
this.element.nativeElement.animate({
translate: { x: 0, y: this.getTranslateYHeight() * -1 },
duration: 750
});
}
    public dismiss(): void {
this.element.nativeElement.animate({
translate: { x: 0, y: this.getTranslateYHeight() },
duration: 750
})
.then(() => this.dismissed.emit(true));
}
    private getTranslateYHeight(): number {
return this.element.nativeElement.getMeasuredHeight() / screenScale;
}
}

implementor.component.html

<GridLayout columns="*,*" rows="auto,*,auto">    
<!-- My Component Page Markup -->
<Button (tap)="onShowTapped($event)"
text="Open" row="0" col="0"></Button>
<Button (tap)="onHideTapped($event)"
text="Close" row="0" col="1"></Button>
    <!-- Snackbar Markup -->
<StackLayout snackbar class="slide" col="0" colSpan="2" row="2">
<Label class="snackbar" text="Hi!"></Label>
</StackLayout>
</GridLayout>

implementor.component.ts

import { Component, ViewChild } from '@angular/core';
import { SnackbarDirective } from './snackbar.directive';
@Component({
selector: 'home',
moduleId: module.id,
templateUrl: './implementor.component.html',
styleUrls: ['./implementor.component.css']
})
export class ImplementorComponent {
@ViewChild(SnackbarDirective) private snack: SnackbarDirective;
    private onOpenButtonTap(): void {
this.snack.show();
}
    private onCloseButtonTap(): void {
this.snack.dismiss();
}
}

implementor.component.css

.snackbar {
text-align: center;
padding: 20;
border-color: red;
border-width: 3;
}

Here’s what’s going on:

using the bracket notation in the directive selector[snackbar] you are able to attach a directive (including components) to elements instead of nesting them inside of other views (explained in the blog post mentioned above). In order to gain access to the directive’s methods, you reference it in the implementing component by type using the ViewChild decorator from angular core@ViewChild(SnackbarComponent). Be aware that if you want to add multiple directives to the view of the same type you will need to use the @ViewChildren() decorator instead and iterate through to find the one you want.

Using this, I have abstracted the show/dismiss functionality away from any specific view and I can bring any view up from the bottom of the screen and am able to dismiss it, using a common directive.

SAMPLE
I have a sample you can pull down from GitHub and play with hosted at https://github.com/ScottMGerstl/nativescript-angular-slidein

Happy Coding!

One clap, two clap, three clap, forty?

By clapping more or less, you can signal to us which stories really stand out.