1

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 { }
Daniel Deulin
  • 65
  • 2
  • 7
  • Since you are using a page router outlet within drawer, it keeps the history of router. Setting `clearHistory` to `true` upon navigation will clear previous pages in the router history. – Manoj Apr 25 '19 at 06:59
  • Thank you for your respond. Changed to "true". Still doesn't work. Edited the question body. – Daniel Deulin Apr 25 '19 at 07:22
  • Can you share a minimal Playground sample where the issue can be reproduced? – Manoj Apr 25 '19 at 08:34
  • Sure. Will try. I will be able to do it in 6-7 hours. – Daniel Deulin Apr 25 '19 at 09:30
  • Here is the playground sample that recreates the problem https://play.nativescript.org/?template=play-ng&id=Lf87p6&v=7 – Daniel Deulin Apr 25 '19 at 17:01
  • I don't see the issue. After navigating to "Topic 2", clicking back button just closes the app not going back to welcome page like you mentioned. – Manoj Apr 25 '19 at 17:05
  • In this case it's my fault as I've described the problem in a wrong way. I need to be able to navigate from "Topic 2" to "Topic 1" or "Topic 3" via SideDrawer. I'm sorry for this misunderstanding – Daniel Deulin Apr 25 '19 at 17:09

1 Answers1

1

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.

Daniel Deulin
  • 65
  • 2
  • 7