Omar Essam Omar Essam - 2 months ago 16
TypeScript Question

Accessing Nativescript custom components

I am learning to build mobile apps using nativescript with angular2, and i created a custom component called booking. I am accessing this custom component from another component called main as shown in these files.

booking.component.ts

import { Component, Renderer, ElementRef, OnInit, ViewChild} from "@angular/core";
import { Page } from "ui/page";
import buttonModule = require("ui/button");
import tabViewModule = require("ui/tab-view");
import {StackLayout} from "ui/layouts/stack-layout";


import colorModule = require("color");
var Color = colorModule.Color;

@Component({
selector: "booking",
templateUrl: "pages/booking/booking.html",
styleUrls: ["pages/booking/booking-common.css", "pages/booking/booking.css"]
})

export class BookingComponent implements OnInit {
oneWay = true;
@ViewChild("oneWay") oneWayButton: ElementRef;
@ViewChild("roundTrip") roundTripButton: ElementRef;
@ViewChild("container") container: ElementRef;




constructor(private page: Page, el: ElementRef, renderer: Renderer) {
renderer.setElementClass(el.nativeElement, 'booking', true);
}

ngOnInit() {
this.toggle();
this.hide();
}
toggle(){
this.oneWay = !this.oneWay;
let oneWayButton = <buttonModule.Button>this.oneWayButton.nativeElement;
let roundTripButton = <buttonModule.Button>this.roundTripButton.nativeElement;
if(this.oneWay){
oneWayButton.backgroundColor = new Color('#fb9900');
roundTripButton.backgroundColor = new Color('#052c5b');
}
else{
oneWayButton.backgroundColor = new Color('#052c5b');
roundTripButton.backgroundColor = new Color('#fb9900');
}
}

hide(){
let container = <StackLayout>this.container.nativeElement;
container.set("visibility","collapsed");
}
show(){
let container = <StackLayout>this.container.nativeElement;
container.set("visibility","visible");
}

getFromList(){
alert("from list");
}
getToList(){
alert("to list")
}
}


main.html

<DockLayout #dock width="100%" height="100%" stretchLastChild="false"

loaded="pageLoaded"
>
<GridLayout columns="*,*,*,*" rows="auto, auto" width="100%" height="auto" class="tabs" dock="bottom">
<StackLayout row = "0" rowSpan = "1" col = "0" colSpan="4" class="dockBorder"></StackLayout>
<StackLayout (tap)="switchTab('booking')" row = "1" rowSpan = "1" col = "0" colSpan="1" class="tab">
<StackLayout class="tabBar activeBar"></StackLayout>
<Image class = "tabIcon" src="~/images/bus.png" ></Image>
<Label text="Booking" class="tabLabel activeLabel"></Label>
</StackLayout>
<StackLayout (tap)="switchTab('hello')" row = "1" rowSpan = "1" col = "1" colSpan="1" class="tab">
<StackLayout class="tabBar"></StackLayout>
<Image class = "tabIcon" src="~/images/bus.png" ></Image>
<Label text="Booking" class="tabLabel"></Label>
</StackLayout>
<StackLayout row = "1" rowSpan = "1" col = "2" colSpan="1" class="tab">
<StackLayout class="tabBar"></StackLayout>
<Image class = "tabIcon" src="~/images/bus.png" ></Image>
<Label text="Booking" class="tabLabel"></Label>
</StackLayout>
<StackLayout row = "1" rowSpan = "1" col = "3" colSpan="1" class="tab">
<StackLayout class="tabBar"></StackLayout>
<Image class = "tabIcon" src="~/images/bus.png" ></Image>
<Label text="Booking" class="tabLabel"></Label>
</StackLayout>
</GridLayout>
<StackLayout>
</StackLayout>
<hello id="hello" #hello></hello>
<booking #booking></booking>

</DockLayout>


main.component.ts

import { Component, ElementRef, OnInit, ViewChild} from "@angular/core";
import { Page } from "ui/page";
import {StackLayout} from "ui/layouts/stack-layout";
import colorModule = require("color");
import {BookingComponent} from "../booking/booking.component"
import {Hello} from "../hello/hello.component"
import {DockLayout} from "ui/layouts/dock-layout";
var Color = colorModule.Color;
@Component({
selector: "main-dock",
templateUrl: "pages/main/main.html",
styleUrls: ["pages/main/main-common.css", "pages/main/main.css"],
})
export class MainComponent implements OnInit{
@ViewChild("booking") booking: ElementRef;
@ViewChild("hello") hello: ElementRef;
active = this.booking;
constructor(private page: Page) {
}
ngOnInit() {
this.page.actionBarHidden = true;
this.switchTab("booking");
}

switchTab(tab){
let b = <BookingComponent>this.booking.nativeElement;
let h = <Hello>this.hello.nativeElement;
if(tab ==="booking" && this.active != this.booking){
h.hide();
b.show();
}
else{
b.hide();
h.show();
}
}
}


everything is working fine but the problem is that when using nativeElement with the custom components it returns undefined; therefore i cant use the custom components methods. can someone show me what I am doing wrong?

Answer

I had this problem too and I don't know it's bug or not, but I found solution for that. use (loaded) event like this:

   <booking #booking (loaded) =onLoaded(booking)></booking>

   onLoaded(booking){
          //booking is equal to this.booking.nativeElement
          //you can use it as you like
   }

related Issue: https://github.com/NativeScript/nativescript-angular/issues/406

UPDATE: I think your problem is because you called this.switchTab("booking"); in ngOnInit use it in ngAfterViewInit but it might have some problems again (see the above link) the solution I mentioned above is the best solution I found.