Home > Net >  Angular - How to directly hook into a loaded instance of a Component from other Components
Angular - How to directly hook into a loaded instance of a Component from other Components

Time:10-16

I'm trying to build a component which directly accesses other components instances --the purpose of this experiment is explore depths of Angular's internals. Let me take my current example: I have a module which contains some 10s of components that render a 2D SVG layout for visualizing geospaces (landscapes), when the user runs the application they see this component already loaded in the UI, I've made another "debug" component (call it DebugComponent), my intended purpose of this component is to directly change the state of another Angular Component by somehow hooking into it's existing instance. So, for example, if a component called HomeComponent has a method named sayHello() which changes the template state of that component, I am basically trying to get my "debug" component have access (or "hook" into already existing components' instance) and change it's state directly without being a descendant or the owner of that component in anyway. I understand that these kind of experiments are not production-usecases and it would be naive to do something like that in Production.

As my limited understanding goes, for communicating between Components, there are multiple supported ways: Globally available RxJS observables, Services & DI framework, @Input() & @Output() decorators, Template Variables (ViewChild, ViewChildren), TemplateRef, ElementRef, and so on.

Angular's ComponentFactoryResolver and ViewContainerRef can be used to dynamically add or remove components to the DOM (which isn't what I'm trying to achieve) but with my limited understanding so far, there is no way to access a "running" instance of a component (access meaning, being able to access members of the class). Dyanmic loading of Components in Angular allows developers to add/remove/ and embed custom components views into the DOM. Like I said, I'm only trying to do this as a fun learning experience but I also plan to build some sort of tiny hooking framework/library within Angular that allows us to globally access any Angular Component on-demand, and modify it's state.

Back in the AngularJS days, DOM manipulations were kind of simpler with the compiler$ service but that's a discouraged use in the recent versions of Angular. The dev team mentions that the Compiler API is for internal uses only and it may change without notice.

Can we somehow access the running instance of a Component from a completely different/unrelated Component either via ComponentFactoryResolver's or ComponentRef or ViewContainerRefs or via the @angular/compiler API?

I apologize for any poor English since I am a non-native.

Any pointers are greatly appreciated, thanks in advance!

CodePudding user response:

It's achievable using the ng variable that Angular exposes in the development mode, given that the component has been rendered in the DOM.

You can grab your component rendered from anywhere with document.getElementsByTagName('<component-selector>') and pass it to ng.getComponent() to get the actual instance.

The ng variable:

Note: Angular exposes this variable only in the development mode and its syntax has been changed in the new Ivy compiler. This example shows the new syntax.

 declare var window:any; //Add this at the top of your file to avoid static type check errors
 ...
    let comp=document.getElementsByTagName('app-home');
        let instance=window.ng.getComponent(comp[0]) as HomeComponent
        console.log('HOME COMP',instance);
        instance.sayHello(); //Would work if HomeComponent exists in the DOM
    
      }
  • Once you have your component instance, you can access all the public properties and even modify them.
  • After modification, remember to use ChangeDetectorRef.detechChanges() to manually trigger Angular's change detection

Here is a detailed example of how to use ng to debug your apps. https://betterprogramming.pub/how-to-debug-angular-ivy-apps-in-the-browser-console-with-ng-950facb490c7

  • Related