Reputation: 28368
My CoreComponent
tells my NotificationsService
to show a new notification and passes an html string in the content
property:
export class CoreComponent {
constructor(private _notificationsService: NotificationsService) {
this._notificationsService.show({content: '<h1 (click)="close()">hej hej</h1>'});
}
}
Then my NotificationsComponent
comes into play after the NotificationsService
have forwarded the notification to the component, this component must render a fake component so all bindings and directives set on the html in content
will work:
export class NotificationsComponent {
public notifications: string[] = [];
constructor(private _notificationsService: NotificationsService, dcl: DynamicComponentLoader, elementRef: ElementRef, injector: Injector) {
_notificationsService.newNotification$.subscribe(
notification => {
this.notifications.push(notification);
if (notification.content) {
dcl.loadIntoLocation(toComponent(notification.content, []), elementRef, 'content');
function toComponent(template, directives = []) {
@Component({
selector: 'custom-content',
template: template,
directives: directives
})
class FakeComponent {}
return FakeComponent;
}
}
}
)
}
}
Then it renders a notification with an *ngFor
loop:
<div>
<ul>
<li *ngFor="#notification of notifications">
<div #content></div>
</li>
</ul>
</div>
The problem though is that it can't find the #content
variable for some reason, it just throws an Uncaught Could not find variable content
. My guess is because it's inside a loop, but I really don't know why if that is the case.
How can I render this fake component into the notifications template (preferably before pushing notification
into public notifications
so the component is actually there from the start when showing a new notification)?
EDIT: I found out that without the *ngFor
my code works, but there is something about the loop that is causing issues here. Does anyone know why this is happening?
Upvotes: 2
Views: 1046
Reputation: 658225
To work around the ngFor
issue you could create a wrapper element that does the actual dcl.loadIntoLocation()
This wrapper component is added for each notification
and gets the comonent passed that it then adds inside itself.
@Component({
selector: 'dcl-wrapper',
template: `<div #target></div>`
})
export class DclWrapper {
constructor(private containerRef:ViewContainerRef, private dcl:DynamicComponentLoader) {}
@Input() component;
ngOnChanges() {
if(this.cmpRef) {
throw 'currently changing type after the component was added is not supported'
}
this.dcl.loadNextToLocation(this.component, this.containerRef).then((cmpRef) => {
this.cmpRef = cmpRef;
});
}
}
@Component({
selector: 'core-comp',
directives: [DclWrapper],
template: `
<h2>Tabs</h2>
<div *ngFor="let notification of notifications">
<dcl-wrapper [component]="notification"></dcl-wrapper>
</div>
`
})
export class NotificationsComponent {
public notifications: string[] = [];
...
}
Like also explained in Angular 2 dynamic tabs with user-click chosen components
Upvotes: 2