Broadcast event in Angular 6 / Typescript

10,936

you can use Subject

export class EventService<T> {
    protected _eventSubject = new Subject();
    public events = this._eventSubject.asObservable();

    dispathEvent(event) {
       this._eventSubject.next(event);
    }
}
Share:
10,936

Related videos on Youtube

Jimmyt1988
Author by

Jimmyt1988

Updated on June 04, 2022

Comments

  • Jimmyt1988
    Jimmyt1988 almost 2 years

    I have the following structure:

    <app>
      <test-a></test-a>
      <test-b></test-b>
    </app>
    
    @Component({
        selector: 'app',
        templateUrl: './app.component.html',
    })
    export class AppComponent {
    }    
    
    @Component({
        selector: 'test-a',
        templateUrl: './testa.component.html',
    })
    export class TestAComponent {
    }
    
    @Component({
        selector: 'test-b',
        templateUrl: './testb.component.html',
    })
    export class TestBComponent {
    }
    

    Test B contains selectable items. When one is selected, i'd like to tell Test A that the item was selected...

    I think there are 2 options i'm aware of that can achieve this.

    • Use App to store the selected item. Modify that selected item in Test B and then allow Test A to react... but it makes an ugly tight coupling between the Test A and Test B components... and the parent App component. I don't like that idea.
    • To create some kind of "Event Subscriber" service that stores an array of various Observables which can be subscribed against. My current implementation here (not finished):

    // Model required for my own class

    export class KeyValuePair<T>
    {
        public key: string;
        public value: T;
    
        construct(key: string, value: T) {
            this.key = key;
            this.value = value;
        }
    }
    

    // How my implementation might look (wip)

    import { Observable, of } from "rxjs";
    import { KeyValuePair } from "../models/keyvaluepair";
    import { Injectable } from "@angular/core";
    
    @Injectable({
        providedIn: 'root',
    })
    export class EventService<T>
    {
        protected subscriptions: KeyValuePair<Observable<T>>[];
    
        public Broadcast(key: string, value: any)
        {
            var observable = new Observable<T>();
            observable.subscribe((a) =>
            {
                return of(value);
            });
    
            this.subscriptions.push(
                new KeyValuePair<Observable<T>>(
                    key, 
                    observable
                )
            );
        }
    
        public Subscribe(key: string): Observable<T>
        {
            var observable = this.subscriptions.find((sub) => {
                return sub.key == key;
            });
    
            return observable.value;
        }
    }
    

    // How you might create a event

    this.testEventService.Broadcast("itemSelected", item);
    

    // How it might be used

    this.testEventService.Subscribe("itemSelected").subscribe((item) => {
        this.changeItem(item);
    });
    

    However, surely i shouldn't have to write this stuff..? In angularjs and jquery there was a $broadcast and $on kind of thing that made life so simple... what am i missing here? Is there an easier way in angular 6 and typescript?

    Edit:

    I have made a service people can use, please tell me if it sucks: https://jsfiddle.net/jimmyt1988/oy7ud8L3/

    • izmaylovdev
      izmaylovdev almost 6 years
      I think that you can make it easier, I can help if you interested.
  • izmaylovdev
    izmaylovdev almost 6 years
    and you can use eventService.events.subscribe(event => {...}) and eventsService.dispatchEvent(event)
  • Jimmyt1988
    Jimmyt1988 almost 6 years
    what would event look like in this case?
  • Jimmyt1988
    Jimmyt1988 almost 6 years
    Oh, i see, this is just a one use kind of thing? how do i assign a key to it? so i can store different events which have different data?
  • izmaylovdev
    izmaylovdev almost 6 years
    whatever you want, in your case you can use something like redux Action - { action: 'itemSelected', payload: {} }
  • izmaylovdev
    izmaylovdev almost 6 years
    you also can create difference selectors from this subject public itemSelectedEvents = this.events.pipe( filter(e => e.action === 'itemSelected'), map(e => e.payload) )
  • izmaylovdev
    izmaylovdev almost 6 years
    "so i can store different events which have different data?" - Yes, you can.
  • Jimmyt1988
    Jimmyt1988 almost 6 years
    Thanks for the help. i'll give this a whirl when I get back from work and give you a tick when I get it to work. thanks man!
  • Jimmyt1988
    Jimmyt1988 almost 6 years
    Thanks, i read up on Subjects too. perfect choice for the job. Odd there is no premade service for this. had to create the entire thing myself :(
  • Jimmyt1988
    Jimmyt1988 almost 6 years
    I've added my final service implementation to the OP. Thanks for your help.
  • izmaylovdev
    izmaylovdev almost 6 years
    here my implementation for that service jsfiddle.net/izmaylovdev/3ybxwuas/13
  • Jimmyt1988
    Jimmyt1988 almost 6 years
    Oh i see, a subject can have multiple objects in it. Good to know! Thanks. Thank you so much man!