I'm trying to implement lateral navigation within my app with the help of a sidedrawer.
My app has a "Start" component which is a kind of a "Welcome" page and 32 "Topics" with necessary content.
I need a user to be able to go from Topic to Topic using Sidedrawer content, without returning to the Start page.
Now I can successfully navigate from the start page to, for example, "Topic 6". But in order to navigate to another Topic, say "Topic 12", I need to press "back" and to return to the start screen. Topic's buttons of the sidedrawer just don't work when I'm on the Topic screen.
Here is the code:
app.component.html with the sidedrawer
<RadSideDrawer [drawerTransition]="sideDrawerTransition">
<GridLayout tkDrawerContent rows="auto, *">
<StackLayout class="sidedrawer-header">
<Image src="res://header" stretch="aspectFit" ></Image>
</StackLayout>
<ScrollView row="1" class="sidedrawer-content">
<StackLayout >
<Button
*ngFor="let topic of topics"
[text]="topic.title"
[class.selected]="isComponentSelected('/unitsContent/' + topic.id)"
(tap)="onNavItemTap('/unitsContent/' + topic.id)"
class="btn">
</Button>
</StackLayout>
</ScrollView>
</GridLayout>
<page-router-outlet tkMainContent></page-router-outlet>
</RadSideDrawer>
app.component.ts
import { Component, OnInit, ViewChild } from "@angular/core";
import { NavigationEnd, Router } from "@angular/router";
import { RouterExtensions } from "nativescript-angular/router";
import { DrawerTransitionBase, RadSideDrawer, SlideInOnTopTransition} from "nativescript-ui-sidedrawer";
import { Topic } from "./data/topic";
import { TOPICS } from "./data/topics-collection";
import { TopicService } from "./data/topic.service";
import { filter } from "rxjs/operators";
import * as app from "tns-core-modules/application";
@Component({
selector: "ns-app",
moduleId: module.id,
templateUrl: "./app.component.html"
})
export class AppComponent implements OnInit {
private _activatedUrl: string;
private _sideDrawerTransition: DrawerTransitionBase;
topics: Topic[];
getTopics(): void {
this.topicService.getTopics()
.subscribe(topics => this.topics = topics);
}
constructor(private router: Router, private routerExtensions: RouterExtensions, private topicService: TopicService) {
// Use the component constructor to inject services.
}
ngOnInit(): void {
this.getTopics();
this._activatedUrl = "/start";
this._sideDrawerTransition = new SlideInOnTopTransition();
this.router.events
.pipe(filter((event: any) => event instanceof NavigationEnd))
.subscribe((event: NavigationEnd) => this._activatedUrl = event.urlAfterRedirects);
}
get sideDrawerTransition(): DrawerTransitionBase {
return this._sideDrawerTransition;
}
isComponentSelected(url: string): boolean {
return this._activatedUrl === url;
}
onNavItemTap(navItemRoute: string): void {
this.routerExtensions.navigate([navItemRoute], {
transition: {
name: "fade"
}, clearHistory: true
});
const sideDrawer = <RadSideDrawer>app.getRootView();
sideDrawer.closeDrawer();
}
}
app-routing.module.ts
import { NgModule } from "@angular/core";
import { NativeScriptRouterModule } from "nativescript-angular/router";
import { Routes } from "@angular/router";
const routes: Routes = [
{ path: "", redirectTo: "/start", pathMatch: "full" },
{ path: "start", loadChildren: "~/app/start/start.module#StartModule" },
{ path: "unitsContent/:id", loadChildren: "~/app/unitsContent/unitsContent.module#UnitsContentModule" },
];
@NgModule({
imports: [NativeScriptRouterModule.forRoot(routes)],
exports: [NativeScriptRouterModule]
})
export class AppRoutingModule { }
app.module.ts
import { NgModule, NO_ERRORS_SCHEMA } from "@angular/core";
import { NativeScriptModule } from "nativescript-angular/nativescript.module";
import { NativeScriptUISideDrawerModule } from "nativescript-ui-sidedrawer/angular";
import { AppRoutingModule } from "./app-routing.module";
import { AppComponent } from "./app.component";
@NgModule({
bootstrap: [
AppComponent
],
imports: [
NativeScriptModule,
AppRoutingModule,
NativeScriptUISideDrawerModule
],
declarations: [
AppComponent,
],
providers: [],
schemas: [
NO_ERRORS_SCHEMA
]
})
export class AppModule { }
unitsContent.component.ts a Topic component
import { Component, OnInit } from "@angular/core";
import { RadSideDrawer } from "nativescript-ui-sidedrawer";
import { ActivatedRoute } from '@angular/router';
import { TopicService} from '../data/topic.service';
import { Topic } from '../data/topic';
import * as app from "tns-core-modules/application";
@Component({
selector: "UnitsContent",
moduleId: module.id,
templateUrl: "./unitsContent.component.html"
})
export class UnitsContentComponent implements OnInit {
topic: Topic;
constructor(
public route: ActivatedRoute,
public topicService: TopicService
) {
// Use the component constructor to inject providers.
}
ngOnInit(): void {
// Init your component properties here.
this.getTopic();
}
getTopic(): void {
const id = +this.route.snapshot.paramMap.get('id');
this.topicService.getTopic(id)
.subscribe(topic => this.topic = topic);
}
onDrawerButtonTap(): void {
const sideDrawer = <RadSideDrawer>app.getRootView();
sideDrawer.showDrawer();
}
}
unitsContent.component.html
<ActionBar class="action-bar">
<NavigationButton ios:visibility="collapsed" icon="res://baseline_menu_white_24" (tap)="onDrawerButtonTap()"></NavigationButton>
<Label class="action-bar-title" [text]="topic.title" horizontalAlignment="left"></Label>
</ActionBar>
<StackLayout>
<GridLayout rows="*, *, *, *" columns="*, *">
<Button text="Button 1" row="0" col="0" rowSpan="3" class="btn"></Button>
<Button text="Button 2" row="0" col="1" rowSpan="3" class="btn"></Button>
<Button text="Button 3" row="3" col="0" colSpan="2" class="btn"></Button>
</GridLayout>
</StackLayout>
unitsContent.module.ts
import { NgModule, NO_ERRORS_SCHEMA } from "@angular/core";
import { NativeScriptCommonModule } from "nativescript-angular/common";
import { UnitsContentRoutingModule } from "./unitsContent-routing.module";
import { UnitsContentComponent } from "./unitsContent.component";
@NgModule({
imports: [
NativeScriptCommonModule,
UnitsContentRoutingModule
],
declarations: [
UnitsContentComponent
],
schemas: [
NO_ERRORS_SCHEMA
]
})
export class UnitsContentModule { }
unitsContent-routing.module.ts it's empty of routs for a while, but I plan to navigate "deeper" later.
import { NgModule } from "@angular/core";
import { Routes } from "@angular/router";
import { NativeScriptRouterModule } from "nativescript-angular/router";
import { UnitsContentComponent } from "./unitsContent.component";
const routes: Routes = [
{ path: "", component: UnitsContentComponent },
];
@NgModule({
imports: [NativeScriptRouterModule.forChild(routes)],
exports: [NativeScriptRouterModule]
})
export class UnitsContentRoutingModule { }
It looks I've found the answer by myself. It turned out to be a pure Angular thing. In my app I'm referring to one and the same component. The only thing that changes is my route parameter. The router only destroys and recreates the component when it navigates to a different route. When only route params or query params are updated but the route is the same, the component won't be destroyed and recreated.
I've found the answer here: Router Navigate does not call ngOnInit when same page
So I modified my unitsContent.component.ts this way:
import { Component, OnInit } from "@angular/core";
import { RadSideDrawer } from "nativescript-ui-sidedrawer";
import { ActivatedRoute } from '@angular/router';
import { TopicService} from '../data/topic.service';
import { Topic } from '../data/topic';
import * as app from "tns-core-modules/application";
@Component({
selector: "UnitsContent",
moduleId: module.id,
templateUrl: "./unitsContent.component.html"
})
export class UnitsContentComponent implements OnInit {
topic: Topic;
constructor(
public route: ActivatedRoute,
public topicService: TopicService
) {
// This part forces the component recreation with the new params
route.params.subscribe(val => {
this.ngOnInit();
});
}
ngOnInit(): void {
// Init your component properties here.
this.getTopic();
}
getTopic(): void {
const id = +this.route.snapshot.paramMap.get('id');
this.topicService.getTopic(id)
.subscribe(topic => this.topic = topic);
}
So it solved my problem.