Search code examples
angularangular-toastr

Toastr passed to child element in angular4


I have a parent component that uses ng2-toastr (4.1.2).

Parent element :

import { Component, ViewContainerRef } from '@angular/core';
    import { AfterViewInit, ViewChild } from '@angular/core';
    import { Router } from '@angular/router';
    declare var jquery: any;
    declare var $: any;
    import { ToastsManager } from 'ng2-toastr/ng2-toastr';

    import { File } from '../models/file';
    import { Tag } from '../models/tag';
    import { Group } from '../models/group';
    import { CmsService } from '../services/cms.service';

    @Component({
        selector: 'app-cms',
        template: `
             <ul *ngFor="let directory of structure?.root.directories">
                <app-directory (refresh)="refresh($event)" [directory]="directory" *ngIf="directory"></app-directory>
                <li *ngFor="let file of directory.files">
                    {{file.name}}.{{file.extension}}
                </li>
            </ul>
        `,
        providers: [
            CmsService
        ]
    })
    export class CmsComponent  {
        structure: any;
        tags: Array<Tag>;
        groups: Array<Group>;
        file: {name: string, firstPageAsCover: boolean, shareable: boolean, tags: Array<{id: number}>};
        directory: {name: string, requiredGroups: Array<{id: number}>};
        constructor (
            private cmsService: CmsService,
            private toastr: ToastsManager,
            private _vcr: ViewContainerRef,
            private router: Router
        ) {
            this.toastr.setRootViewContainerRef(_vcr);
        }
    }

Child element

import { Component, Input, Output, ViewContainerRef, EventEmitter } from '@angular/core';
import { Router } from '@angular/router';
declare var jquery: any;
declare var $: any;
import { ToastsManager } from 'ng2-toastr/ng2-toastr';

import { File } from '../models/file';
import { Directory } from '../models/directory';
import { CmsService } from '../services/cms.service';

@Component({
    selector: 'app-directory',
    template: `
        <li class="directory" data-id="{{directory.id}}">
            <a (click)="toggle($event.target, directory.id)">+</a>
            {{directory.name}}
            <a class="action addFolder" (click)="addDirectory(directory)"></a>
            <a class="action editFile" (click)="editDirectory(directory)"></a>
            <a class="action addFile" (click)="add(directory)"></a>
            <ul class="sub d-none">
                <app-directory *ngFor="let dir of directory.directories" (refresh)="refreshChild($event)" [directory]="dir"></app-directory>
                <li class="file" *ngFor="let file of directory.files">
                    <a (click)="displayFile(file.id)">
                        {{file.name}}.{{file.extension}} | {{file.sizeInBytes / 1024}} kb | {{file.lastModified}} | {{file.timesViewed}}
                    </a>
                    <a class="action editFile" (click)="edit(file)"></a>
                    <a class="action link" (click)="link(file.id)"></a>
                    <a class="action download" (click)="download(file.id)"></a>
                    <a class="action delete" (click)="delete(file.id)"></a>
                </li>
            </ul>
        </li>
    `,
    providers: [
        CmsService
    ]
})
export class DirectoryComponent  {
    @Output() refresh: EventEmitter<any> = new EventEmitter();
    @Input() directory: Directory;
    constructor (
        private cmsService: CmsService,
        private toastr: ToastsManager,
        private _vcr: ViewContainerRef,
        private router: Router
    ) {
        this.toastr.setRootViewContainerRef(_vcr);
    }

    ngOnInit() {
        this.toastr.success('cucu', 'cucu');
    }
}

When I try to enable the toastr in the child element, it only works first time it's loaded. Then I have this message :

ERROR Error: Uncaught (in promise): Error: ViewDestroyedError: Attempt to use > a destroyed view: detectChanges

Also, the toastr doesn't work anymore on the parent element.

Please note that the child element is recursive.

Thanks !


Solution

  • You need to set setRootViewContainerRef only on root element.

    So remove this.toastr.setRootViewContainerRef(_vcr); on child component and you will be fine.