Reputation: 1027
Is there a way in Angular to project content from one component into a "container" in another component? Not from parent to child, which can be done with ng-content, but from a component to its cousin (via the parent).
In our application we have layout in the app component that splits the page into 3 elements: side menu, static header and main content panel.
Inside the content panel we've got router-outlet which renders content of the smart components. We wish to project some of that content to the header for example.
Below is very simplified example of the app structure. The difficulty is that different pages need to project vastly different contents, thus cannot easily be done by one, data-driven component.
We would like to avoid having a bunch of smart components conditionally referenced in the header and displayed based on what page is currently loaded in the main panel.
<app>
<side-menu>...</side-menu> <-- menu component
<header> <-- header component
<section>Static header content</section>
<section> ## Project content here ## </section>
</header>
<main>
<router-outlet></router-outlet> <-- page components
</main>
</app>
We tried looking into template outlet, but we couldn't wire up template defined in one component to the outlet in another.
Upvotes: 1
Views: 1128
Reputation: 1826
You could use a service with a behaviorSubject of templateRef in it.
import { Injectable, TemplateRef } from "@angular/core";
import { BehaviorSubject } from "rxjs";
@Injectable()
export class TemplateService {
sharedTemplateSubject: BehaviorSubject<
TemplateRef<any>> = new BehaviorSubject<TemplateRef<any>>(null);
sharedTemplate$ = this.sharedTemplateSubject.asObservable();
constructor() {}
}
Now all you need to do is to subscribe to this server sharedTemplate$ variable and when it emits render this template where ever you want it to go using the viewContainerRef and createEmbededView
export class AppComponent implements OnInit {
@ViewChild("container", { read: ViewContainerRef })
container: ViewContainerRef;
constructor(private templateService: TemplateService) {}
ngOnInit() {
this.templateService.sharedTemplate$.subscribe(template => {
this.container.createEmbeddedView(template);
});
}
}
Upvotes: 3
Reputation: 126
If I understand the issue correctly, I would recommend using a Service.
import { Injectable } from '@angular/core';
@Injectable()
export class CustomService{
sharedContent: string = 'test';
}
From here you can set/get this string from any of your components.
import { Component, OnInit } from '@angular/core';
import { CustomService } from './services/custom-service.service';
@Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.scss'],
})
export class HomeComponent implements OnInit {
sharedContent: string;
constructor(private customService: CustomService) {
this.sharedContent = this.customService.sharedContent;
}
changeContent(): void {
this.customService.sharedContent = 'new test';
}
}
Upvotes: 0