简体   繁体   中英

Dynamically child component in parent

I'm building an app with Angular4 and Vmware's Clarity UI for Angular. I have a main header for navigating the app. There are some views within the app, that don't need a sidebar and other that do. I want to display a sidebar specific to a particular view if the view has one, when a user navigates to it. I'm also using module level routing in my application.

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { MainComponent } from './main.component';

const routes: Routes = [
    {
        path: '', component: MainComponent,
        children: [
            {
                path: 'dashboard',
                loadChildren: './dashboard/dashboard.module#DashboardModule',
                data: {
                    title: 'Dashboard',
                    showSideNav: false
                }
            },
            {
                path: 'sales',
                loadChildren: './sales/sales.module#SalesModule',
                data: {
                    title: 'Sales',
                    showSideNav: true
                }
            }
        ]
    }
];

@NgModule({
    imports: [RouterModule.forChild(routes)],
    exports: [RouterModule]
})
export class MainRoutingModule { }

This is MainComponent

import { Component, OnInit } from '@angular/core';
import { Router, NavigationEnd, ActivatedRoute } from '@angular/router';

@Component({
    selector: 'app-main',
    templateUrl: './main.component.html',
    styleUrls: ['./main.component.scss']
})
export class MainComponent implements OnInit {

    showSideNav: Boolean = false;

    constructor(public router: Router, public activatedRoute: ActivatedRoute) { }

    setSidenavState() {
        this.router.events
            .filter(event => event instanceof NavigationEnd)
            .map(() => this.activatedRoute)
            .map(route => {
                while (route.firstChild) {
                    route = route.firstChild;
                }

                return route;
            })
            .filter(route => route.outlet === 'primary')
            .mergeMap(route => route.data)
            .subscribe((event) => { 
                this.showSideNav = event['showSideNav'];
                console.log(this.showSideNav);
            });
    }
    ngOnInit() {
        this.setSidenavState();
        if (this.router.url === '/') {
            this.router.navigate(['/dashboard']);
        }
    }

}

and this is the main template

<clr-main-container>
    <header class="header header-6">
        <div class="branding">
            <a routerLink="/dashboard" class="brand nav-link">
                <img src="assets/img/logo-white.png">
            </a>
        </div>
        <div class="header-nav">
            <a routerLink="/dashboard" routerLinkActive="active" class="nav-link nav-text">Dashboard</a>
            <a routerLink="/sales" routerLinkActive="active" class="nav-link nav-text">Sales</a>
            <a href="" class="nav-link nav-text">Purchases</a>
            <a href="" class="nav-link nav-text">Contacts</a>
            <a href="" class="nav-link nav-text">Reports</a>
        </div>
    </header>
    <div class="content-container">
        <div class="content-area">
            <router-outlet></router-outlet>
        </div>
        <nav class="sidenav" *ngIf="showSideNav">
            <app-sidenav></app-sidenav>
        </nav>
    </div>
</clr-main-container>

Within the main component, i have setup like this

+-- dashboard
+-- sales
|   +-- sidenav
+-- sidenav
|   +-- sidenav.component.html
|   +-- sidenav.component.ts
+-- main-routing.module.ts
+-- main.component.html
+-- main.component.ts
+-- main.module.ts

My question is how do I inject a different sidenav component specific to a particular view into the app-sidenav component if the showSideNav property is set to true . Any suggestions or links would be appreciated.

I believe the cleanest way to solve your use case is simply to move a little bit of the layout to the actual routed component. Right now, you have this in your main template:

<div class="content-container">
    <div class="content-area">
        <router-outlet></router-outlet>
    </div>
    <nav class="sidenav" *ngIf="showSideNav">
        <app-sidenav></app-sidenav>
    </nav>
</div>

and let's say you sales template looks like this:

<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>

By shifting down the sidenav into the routed components, your main template becomes:

<div class="content-container">
    <router-outlet></router-outlet>
</div>

and your sales template becomes:

<div class="content-area">
    <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
</div>
<nav class="sidenav">
    <sales-sidenav></sales-sidenav>
</nav>

If a component doesn't have a sidenav, simply do not put the sidenav in its template. No need for an *ngIf . The result is that you don't pollute your routes with sidenav information anymore, you just leave it to the component that handles the route itself, becomes it's the one that should own the specific sidenav logic.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM