angular inject component into another layout component

Viewed 1026

I'm trying to inject a component into another layout component? I'm trying to do that with a service but nothing works.

My layout is:

AppComponent
       |
AppLayoutComponent
       |
------------------------------------------------------------
       |                             |                     |
SecondarySidebarComponent     DashboardComponent   RightSidebarComponent

I'm trying to inject HelloWorldComponent into SecondarySidebarComponent from DashboardComponent

app-layout.component.html

        <!-- Secondary sidebar-->
        <template #secondarysidebar></template>
        <!-- /secondary sidebar -->

        <!-- Main content -->
        <div class="content-wrapper">

            <!-- Page header -->
            <app-page-header></app-page-header>
            <!-- /page header -->

            <!-- Tabbar -->

            <!-- /tabbar -->

            <!-- Content area -->
            <div class="content">
                <router-outlet></router-outlet>
            </div>
            <!-- /content area -->

dashboard.component.ts

import { Component, OnInit, AfterContentInit, TemplateRef, ViewChild } from '@angular/core';
import { SecondarySidebarService } from '../shared/services/secondary-sidebar.service';
import { RightSidebarService } from '../shared/services/right-sidebar.service';

@Component({
  selector: 'app-dashboard',
  templateUrl: './dashboard.component.html',
  styleUrls: ['./dashboard.component.scss']
})
export class DashboardComponent implements AfterContentInit {
  @ViewChild(TemplateRef) secondarysidebar: TemplateRef<any>;

  constructor(private rightsidebar: RightSidebarService, private sidebar: SecondarySidebarService) { 

  }

  ngAfterContentInit() {
    this.sidebar.open(this.secondarysidebar);
  }

}

secondary-sidebar.service.ts

import { Injectable, ComponentFactoryResolver, Injector, Inject, TemplateRef, ApplicationRef, Type, ViewChild, ViewChildren, ViewContainerRef } from '@angular/core';
import { DOCUMENT } from '@angular/common';
import { SecondarySidebarComponent } from '../layouts/secondary-sidebar/secondary-sidebar.component';

export type Content<T> = string | TemplateRef<T> | Type<T>;

@Injectable({
  providedIn: 'root'
})
export class SecondarySidebarService {
  @ViewChild('secondarysidebar') secondarysidebar; 

  componentRef: any;

  constructor(private resolver: ComponentFactoryResolver,
    private injector: Injector,
    private appRef: ApplicationRef,
    @Inject(DOCUMENT) private document: Document,
  ) { }

  open<T>(content: Content<T>) {
    console.log('try to load component...');
      const factory = this.resolver.resolveComponentFactory(SecondarySidebarComponent);
      this.componentRef = this.secondarysidebar.createComponent(factory);
  }

}

Where i'm wrong ??

Thank You.

1 Answers

This line: @ViewChild('secondarysidebar') secondarysidebar; in secondary-sidebar.service.ts seems fishy, because services usually don't have html-templates and therefor cannot have viewchildren. I assume with the viewchild you want to load the template from app-layout.component.html?

To be able to do it like that, you would need to make your SecondarySidebarService a directive from which your dashboard.component.ts inherits. (But then you couldn't inject it into your sidebar component, to render the content.)

The best Solution for this would probably be to create a Viewportal (https://material.angular.io/cdk/portal/overview) in your SecondarySidebarComponent so any components, that are in a different branch of your dom, can render components inside your SecondarySidebarComponent.

I created a stackblitz for you, that demonstrates a simple implementation for your usecase. https://stackblitz.com/github/Narmor/angular-view-portal

In the example anything that is inside a a app-sidebar-header-portal tag will be rendered in the sidebar component. No matter where it is used inside the application.

<app-sidebar-header-portal>
  Hello World!
</app-sidebar-header-portal>

It is recommended to create components for content that is rendered somewhere else in the app through a portal, because otherwise the style encapsulation will prevent you from styling the content. (If you create a component, the whole component will be rendered within the portal, which leads to the styles of the component being applied.)

Related