0

I am loading a component dynamically and it is working fine apart from I can make it to be destroyed.

My component that is being loaded dynamically

import { Component, ElementRef, ComponentRef } from '@angular/core';

@Component({
    moduleId: module.id,
    selector: 'app-user-list',
    templateUrl: 'user-list.component.html',
})
export class UserListComponent {
    _componentRef: ComponentRef<any>;

    constructor(private _elementRef: ElementRef) {}
    removeComponent()
    {
        this._componentRef.destroy();
    }
}

And in html of this component I have just a button to remove it, something like it

<button (click)="removeComponent()">Remove Component</button>

However, when removeComponent() fires an error is thrown

TypeError: Cannot read property 'destroy' of undefined

What I am missing?

UPDATE
More explanation about the issue: [1] I have user.component and user-list.component. [2] There is a button in the user.component to call user-list.component [3] When this button is clicked, user-list.component should load in a specific area, which is working. [4] There is a button in the user-list.component to close this component that was loaded dynamically. [5] When this buttons is clicked, user-list.component should be destroyed.

UserComponent

import { Component, DynamicComponentLoader, Injector, ApplicationRef } from '@angular/core';

import { UserListComponent } from "../user-list/user-list.component";

@Component({
    moduleId: module.id,
    selector: 'app-users',
    templateUrl: 'users.component.html',
    styleUrls: ['users.component.css'],
    directives: [TestComponent, CreateUserForm]
})
export class UsersComponent implements OnInit, AfterViewInit {

    public constructor(
        private _dcl: DynamicComponentLoader,
        private _injector: Injector,
        private _appRef: ApplicationRef
    ){}

    loadUserList()
    {
        this._dcl.loadAsRoot(UserListComponent, '#user-list', this._injector)
            .then((compRef: ComponentRef<UserListComponent>) => {
                (<any>this._appRef)._loadComponent(compRef);

                return compRef;
            });

    }

}

However, I've heard that load component dynamically that way is deprecated. We should use ComponentResolver and ViewContainerRef. Is that right?

Tiago Matos
  • 1,586
  • 1
  • 20
  • 29
  • 1
    You're not assigning any value to `_componentRef`, that's why it's undefined. Btw, what do you mean by "loaded dynamically"? – martin Jul 29 '16 at 07:00
  • Please update your question with full code. – micronyks Jul 29 '16 at 07:04
  • 1
    Have a look at https://medium.com/tixdo-labs/angular-2-dynamic-component-loader-752c3235bf9#.tu6gcgw69 it shows how to get a `ComponentRef` – raphaëλ Jul 29 '16 at 07:46
  • Hi guys, I just updated my questions. Please tell me if it still not clear – Tiago Matos Aug 01 '16 at 00:31
  • DCL is deprecated. Use `ViewContainerRef.createComponent()` instead. See http://stackoverflow.com/questions/36325212/angular-2-dynamic-tabs-with-user-click-chosen-components/36325468#36325468 for an example. – Günter Zöchbauer Aug 01 '16 at 05:27
  • I solve my problem using this source https://www.lucidchart.com/techblog/2016/07/19/building-angular-2-components-on-the-fly-a-dialog-box-example/ – Tiago Matos Aug 02 '16 at 01:28

2 Answers2

0

this._componentRef should be undefined in your case.

you have to make sure that you assign component instance to _componentRef,

dcl.loadNextToLocation(UserListComponent, viewContainerRef)  //<----this line... whatever it is in your case
.then((ref) => {
      ref.instance._componentRef = ref;                      //<----this assignment is required
      ...
});

Then you will be able to destroy it for sure.

micronyks
  • 54,797
  • 15
  • 112
  • 146
  • I can't use loadNextToLocation because I need to load in a specific spot! – Tiago Matos Aug 01 '16 at 00:39
  • Anyway, I've added this reference instance and the component is being removed but I am getting this error: zone.js:260 Uncaught Attempt to use a destroyed view: detectChanges. Also, I can't load the component again! – Tiago Matos Aug 01 '16 at 00:51
0

You need to do a check before destroying it:

import { Component, ElementRef, ComponentRef } from '@angular/core';

@Component({
    moduleId: module.id,
    selector: 'app-user-list',
    templateUrl: 'user-list.component.html',
})
export class UserListComponent {
    _componentRef: ComponentRef<any>;

    constructor(private _elementRef: ElementRef) { }
    removeComponent() {
        if (this._componentRef) {
            this._componentRef.destroy();
        }
    }
}
Aldracor
  • 2,133
  • 1
  • 19
  • 27