The "Problem"
While working on a simple application I wanted to show some content in the title / header bar, but this should be only visible on a specific route.
header.component.html:
<div class="header">
<ng-container *ngIf="!showSuperSelection">{{ title }}</ng-container>
<!-- this component is only needed in an "/selected-page" - route -->
<app-your-big-component *ngIf="showSuperSelection">
</app-your-big-component>
</div>
1st solution: *ngIf
- "just" hide (
*ngIf="showSuperSelection"
, exampled in the problem) the content in the header-bar until the specific route was opened
Pro's | Con's |
---|---|
easy to use, just an *ngIf
|
its "bad" if this content is a bigger component (byte size), which adds a lot of to the first loading time (every byte counts), which is only "ok" if you are building an intranet-application |
2nd solution: Service - ng-template - template outlet
- You could create a directive to get
TemplateRef
- then using a service to save that reference
- then in your target view, get this reference and use it like
<ng-container *ngIf="templateToShow$ | async as templateRef"
[ngTemplateOutlet]="templateRef">
</ng-container>
There you have your dynamic templates / layout parts in your app.
Pro's | Con's |
---|---|
now this template would be only visible when you need it, and also not adding additional bytes to load | you would've to do it for every part you need |
My solution: 🚀
npm install @gewd/ng-utils -S
Building up on the 2nd's solution, I kinda wanted to have it a bit more dynamic, so I refacted it to be used on a ID per portal/source.
import { DynamicPortalModule } from '@gewd/ng-utils/dynamic-portal';
@NgModule({
imports: [
// ...
DynamicPortalModule
]
})
header.component.html:
<div class="header">
<dynamic-portal key="headerSelection" class="your-style">
{{ title }}
</dynamic-portal>
</div>
selected-page.component.html: which is a lazy-loaded route
<div class="stuff">
Much stuff, details, you name it :-)
</div>
<ng-template dynamicPortalSource="headerSelection">
<app-your-big-component></app-your-big-component>
</ng-template>
> Demo < -> Open the Dynamic Portal Component
Part
Pro's | Con's |
---|---|
portal's / portal-sources can be placed anywhere | you'd need to use this package or copy it 😁 |
Any ideas / issues / suggestions, write here or open an issue :)
Top comments (13)
Hi!
I’d follow this approach:
Then, in your directive, you’d inject the ActivatedRoute and the ViewContainerRef and based on your logic, you’d render one component from the array(meaning that you’d also inject DYNAMIC_HEADER_INJECTOR).
Hi :)
Back to topic:
I haven't thought about doing this with injection tokens, lets play it out:
but wouldn't it be then like in the
1st solution
?The components would have to be registered and imported to the AppModule which ends-up raising the initial load of your app
Thats why I wanted to have it loaded only where it really needed to be (and not in the AppModule in my case)
or did I misunderstood your idea?
No, you’re right.
I think there is a way to mitigate this issue, but this implies more work from the developer.
If we don’t want to include the component in the main bundle, we can put it in its module and in the directive, based on some conditions, you can load the module on demand by using import(path/to/module).then() and injecting the compiler.
Yeah like you wrote, another way would be to lazy-load the components of it, there are some helper libaries for this.
I also have one 😁
Lazy Loaded Components - #4 NPM-Package
negue ・ Dec 25 ・ 2 min read
Thanks for sharing!
I’m skeptical about libraries, but I do like to explore them!
That's a cool article. Not sure why it hasn't more likes and stuff. Because of Christmas maybe?
Hehe thank you!
Yeah I wish I'd know why ^^, maybe not enough tags?
Maybe the point of time when you posted this? I also found that a little advertisement on Twitter and Reddit helps.
When is the best time to post? I don't really have a clue there ^^
On my next I'll try twitter / reddit
As for my own posts I can definitely say that they received more attention on regular work days. Apart from that I am really not sure :)
Just an idea. Create a header component with just a ngcontent tag.
Now create a Header1 and Header2 component. On each page inject header1 or header2.
You can default the header component to header1 and use flags to hide it when header2 is injected.
You can also use grid template areas for "header" "main" and "footer" areas.
Hey!
yeah this could be also a valid workaround too. If every (lazy-loaded) page has its own header/content/footer then this would be a valid option.
In my projects I mostly want to have the header only once created in a root (or the App itself) and under that header, comes the
<router-outlet></router-outlet>
.But yeah then comes the niche-issue "I want to have a different header just for this one route".
Understood, that design requires a smart overideable header component. Something easily done using Event services. But will still require notification when other header is wanted.