Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to display single instance of an angular component in multiple places?

Tags:

angular

Let's say I have html like this:

      <div *ngIf="(isVisible | async)">
        <app-mycomponent></app-mycomponent>
      </div>
      <div *ngIf="!(isVisible | async)">
        <app-mycomponent></app-mycomponent>
      </div>

with a button that toggles isVisible. This creates a new component instance each time I toggle the visibility.

So my question is: Can I change the implementation to have same instance of AppMyComponent to be used when visibility is toggled. E.g. by having a wrapper component that adds the app-mycomponent dynamically or something.

EDIT: My real case is quite complex and even though this example does not make sense, I'm very much interested can this be done.

EDIT2: Here's stackbliz that solves my problem.

like image 350
char m Avatar asked Jul 05 '19 09:07

char m


People also ask

Can we create multiple instances of service in Angular?

It will create multiple instances of a service. Every time a new instance of provided service will be created when a component is used inside another component.

Can a component have multiple templates Angular?

You can simply extend your base component and overwrite the template. This allows you to have different components with the exact same functionality, but different templates.

How many instances of service is created in Angular?

In this article we'll explore when and why Angular creates two instances of the same service and what solutions exist to ensure a service remains a singleton in the entire application.

Can two components have same name in Angular?

Two or more components use the same element selector. Because there can only be a single component associated with an element, selectors must be unique strings to prevent ambiguity for Angular.


1 Answers

This answer is based on the stackblitz example provided in this answer to a similar question I asked.

Step #1: Create a directive that you will use wherever you want to have your reusable component.

@Directive({
  selector: "[reusable-outlet]",
})
export class ReusableDirective implements OnInit {
  constructor(
    private viewContainerRef: ViewContainerRef,
    private reusableService: ReusableService
  ) {}

  public ngOnInit(): void {
    this.reusableService.attach(this.viewContainerRef);
  }
}

Step #2 Create the service that will be in charge of:

  • dynamically creating the component that will be reused
  • attaching and detaching that component to the view container of the directive created in step ~1.

Note: Knowing when to detach the component is based on router events, but it should be possible to base it on messages instead, if you need to change where your component is without having navigation changes.

@Injectable()
export class ReusableService {
  private componentRef: ComponentRef<ReusableComponent>;

  private currentViewContainerRef: ViewContainerRef;

  constructor(
    private componentFactoryResolver: ComponentFactoryResolver,
    private injector: Injector,
    private router: Router
  ) {
    const componentFactory =
      this.componentFactoryResolver.resolveComponentFactory(ReusableComponent);
    this.componentRef = componentFactory.create(injector);

    this.router.events.subscribe((event) => {
      if (event instanceof NavigationStart && this.currentViewContainerRef) {
        this.detach(this.currentViewContainerRef);
      }
    });
  }

  public attach(viewContainerRef: ViewContainerRef) {
    this.currentViewContainerRef = viewContainerRef;
    viewContainerRef.insert(this.componentRef.hostView);
  }

  public detach(viewContainerRef: ViewContainerRef) {
    viewContainerRef.detach(
      viewContainerRef.indexOf(this.componentRef.hostView)
    );
  }
}

like image 77
David Avatar answered Oct 13 '22 19:10

David