Skip to content

Instantly share code, notes, and snippets.

@Armenvardanyan95
Created April 9, 2025 10:52
Show Gist options
  • Save Armenvardanyan95/f74e01d396ff39bca373c0b1b7be7f0a to your computer and use it in GitHub Desktop.
Save Armenvardanyan95/f74e01d396ff39bca373c0b1b7be7f0a to your computer and use it in GitHub Desktop.
@Injectable({providedIn: 'root'})
export class PortalService {
// we can have multiple portals
portals = signal<Record<string, TemplateRef<any>>>({});
// get one of the templates to use in your component
getPortal(portalName: string) {
return computed(() => this.portals()[portalName]);
}
// add a new template
setPortal(portalName: string, template: TemplateRef<any>) {
this.portals.update(portals => ({
...portals,
[portalName]: template
}));
}
}
@Directive({
selector: '[appPortal]',
})
export class PortalDirective implements AfterViewInit {
portalName = input.required<string>({alias: 'appPortal'});
templateRef = inject(TemplateRef);
portalService = inject(PortalService);
ngAfterViewInit(): void {
// pick up the template and send it to whenever we want it projected
this.portalService.setPortal(this.portalName(), this.templateRef);
}
}
@Component({
selector: 'app-header',
template: `
<header>
Ng App
@if (headerTemplate()) {
// get the particular template and project it in another component
<ng-container *ngTemplateOutlet="headerTemplate()"/>
}
</header>
`, imports: [NgTemplateOutlet]
})
export class HeaderComponent {
portalService = inject(PortalService);
headerTemplate = this.portalService.getPortal('header');
}
// then, somewhere in some template:
<span *appPortal="'header'">Some Content</span>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment