Search code examples
angularweb-componentangular10

How to input an observable into an Angular web component


Please note that this question is NOT about regular Angular components. I'm specifically asking about a reusable custom element created with Angular also called an Angular web component.

I have a reusable Angular 10 web component being hosted inside another Angular 10 web app. Using attribute names that are dash-separated lowercase(i.e. my-data), I'm able to input a string to an Angular web component that has an @Input with lower camel case(i.e. myData).

HOST APP has the following in it's markup:

<my-custom-element my-data="test"></my-custom-element>

REUSABLE WEB COMPONENT - my-custom-element:

@Input() myData: string;

The string works fine and does get passed into the web component. Now, how do I pass an observable to the web component? Example (this does not work as it is taking what's inside the "" as a literal string.)

HOST APP MARKUP:

<my-custom-element 
    my-data="test"
    fetch-event="eventsSubject.asObservable()"
></my-custom-element>

HOST APP COMPONENT:

eventsSubject: Subject<void> = new Subject<void>();

 handleButtonClick(event: any): void {
   this.eventsSubject.next();
}

REUSABLE WEB COMPONENT - my-custom-element:

@Input() myData: string;
@Input() fetchEvent: Observable<void>;

I also tried the following which also doesn't work: [fetch-event]="eventsSubject.asObservable()"

If using @Input to pass in an observable to Angular web components is not the way to do it, please let me know. I also tried this.elRef.nativeElement.attributes['fetchEvent'].value which also didn't work for me.


Solution

  • After lots of research and finding out one cannot pass in complex data into Angular Web Component via @Input, this is what I did and has worked well for me so far.

    Since @Outputs of Angular Web Component do allow for more than just strings to be passed out, I created the observable inside the web component instead, immediately subscribe to listen for events, and immediately passed this to the Angular host app. Then in the host app, that observable is received via markup and used to broadcast an event to the listening web component.

    Web component(my-custom-element is the selector being set as the name of the exported component inside ngDoBootstrap() of my app.module.ts):

    @Output() setUpObservable = new EventEmitter<Subject<void>>();
    eventsSubject: Subject<void> = new Subject<void>();
    fetchEvent: Observable<any>;
    
    ngOnInit(): void {
       eventsSubject: Subject<void> = new Subject<void>();
         fetchEvent: Observable<any>;
    
       this.fetchEvent = this.eventsSubject.asObservable();
           this.eventSubscription = this.fetchEvent.subscribe((x) => {
             // some code in here that I did not want to run until it was initiated by the host app
           });
           this.setUpObservable.emit(this.eventsSubject); // immediately send out the observable
    }
    

    Host app markup:

    <my-custom-element 
        (setUpObservable)="handleSetUpObservable($event)"
    ></my-custom-element>
    

    Host app component:

    eventsSubject: Subject<void> = new Subject<void>();
    
    onButtonClick(): void {
     this.eventsSubject.next(someData); // this talks to the Web component to tell it to do stuff
    }
    
    handleSetUpObservable(event: CustomEvent): void {
        this.eventsSubject = event.detail.observers[0];
    }