Chrillewoodz
Chrillewoodz

Reputation: 28368

Unable to find variable inside *ngFor in Angular 2

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

Answers (1)

G&#252;nter Z&#246;chbauer
G&#252;nter Z&#246;chbauer

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

Related Questions