How to subscribe object from service in Angular 2/5?

12,567

You can create a subscription in your service that notifies if event list changed

eventChanged = new Subject<Event[]>();

in your component, you'll want to subscribe to the eventChanged, in case event list has changed

this.subscription = this.eventService.eventChanged
  .subscribe(
    (event: Event[]) => {
      this.events = events;
    }
  );

Then add a next in your service to notify of event changed every time any component updates it, and make it resend the list of events, or whatever you want

  addEvent(event: Event) {
    this.events.push(event);
    this.eventChanged.next(this.events.slice());
  }

Update: With example

In case we have event viewer, event editor components, and event service

Setup event service to have a subject (event changed), accessor (get events) adder (update events)

import { Injectable } from '@angular/core';
import {Subject} from 'rxjs/Subject';

@Injectable()
export class EventService {

  eventChanged = new Subject<string[]>();

  events: string[] = [
    'Pizza Party',
    'Hackacthon',
    'Movie Night'
  ]
  constructor() { }

  addEvent(event: string) {
    this.events.push(event);
    this.eventChanged.next(this.events.slice());
  }

  getEvents() {
    return this.events.slice();
  }
}

Then component EventViewer, gets the list, as well as subscribes for any changes

event-viewer.component.ts

import { Component, OnInit } from '@angular/core';
import {EventService} from '../event.service';
import {Subscription} from 'rxjs/Subscription';

@Component({
  selector: 'app-event-viewer',
  templateUrl: './event-viewer.component.html',
  styleUrls: ['./event-viewer.component.css']
})
export class EventViewerComponent implements OnInit {

  subscription: Subscription;
  events: string[] = this.eventService.getEvents();

  constructor(private eventService: EventService) { }


  ngOnInit() {
    this.subscription = this.eventService.eventChanged
    .subscribe(
      (events: string[]) => {
        this.events = events;
      }
    )
  }

}

So then we render it out

event-viewer.component.html

<ul>
  <li *ngFor="let event of events">{{event}}</li>
</ul>

Lastly we want an event editor component

event-editor.component.ts

import { Component, OnInit } from '@angular/core';
import {EventService} from '../event.service';

@Component({
  selector: 'app-event-edit',
  templateUrl: './event-edit.component.html',
  styleUrls: ['./event-edit.component.css']
})
export class EventEditComponent implements OnInit {

  eventNumber: number = 1;

  constructor(private eventService: EventService) { }

  ngOnInit() {
  }

  addEvent()
  {
    this.eventService.addEvent(this.eventNumber.toString())
    this.eventNumber++;
  }

}

and render a button for the user to control

event-editor.component.ts

<button (click)="addEvent()">Add event {{eventNumber}}</button>

In the module of choice we'll obviously have to declare these components, enlist the provider

app.module.ts

@NgModule({
  declarations: [
    EventViewerComponent,
    EventEditComponent
  ],
  imports: [
    CommonModule
  ],
  providers: [EventService]
})

So then in then we render both components

app.component.ts

<app-event-viewer></app-event-viewer>
<app-event-edit></app-event-edit>

Now every time we click on button in one component, the other component gets the updated list enter image description here

Share:
12,567

Related videos on Youtube

Adriano
Author by

Adriano

Updated on June 04, 2022

Comments

  • Adriano
    Adriano almost 2 years

    I have issue where I want to receive data into my property component after they came from the server.

    I made something like this in Service:

    private events: Event[] = [];
    eventChanged = new Subject<any>(); // Edit: added an observable
    
    constructor(private http: HttpClient) { 
        this.http.get<Event[]>(this.baseUrl)
        .subscribe(events => this.events = events);
      this.eventChanged.next(this.events.slice()); //Edit: added an information to subscribers that events list changed
    }
    getEvents(): Observable<Event[]> {
        return this.eventChanged.asObservable();
    }  // Edit: now I use this method to enables subscribers to observable
    
            /* I don't use that method after Edit
            showAllEvents(): Event[] {
                return [...this.events];
            }
            */
    

    And then I use method showAllEvents() into mine component like this:

    private events: Event[] = [];
    private calendarEvents: CalendarEvent[] = [];
    subscription: Subscription; // Edit: Added a Subscription
    
        getInterestedEvents() {
           // this.events = this.el.showAllEvents(); <-- I changed it into observable
       this.subscription = this.el.getEvents()
        .subscribe(
        (events) => {
          this.events = events;
        });
        this.events.forEach(eachEvent => {
            let calendarEvent: CalendarEvent = {
                start: subDays(startOfDay(new Date()), 1),
                end: addDays(new Date(), 1),
                title: eachEvent.name,
                color: colors.red
            }
            this.calendarEvents.push(calendarEvent);
        })
    }
    

    I don't know how to make this.events to wait for data from service. Any ideas? On every page it looks different and now I feel like a fool.

    Edit

    I made a subscribe and observable but still this.el.getEvents().subscribe... dosen't return any data in my component.

  • Adriano
    Adriano over 6 years
    Unfortunately it doesn't work, I add this.eventChanged.next(this.events.slice()); in mine Service constructor and I also test method addEvent() and this.eventService.eventChanged.subscribe(.. didn't notice any changes. It was not called again.
  • Iancovici
    Iancovici over 6 years
    @Adriano, created a complete example
  • Adriano
    Adriano over 6 years
    @lancovici That subscribing don't works when I get data from server. Only thanks to this : events: string[] = this.eventService.getEvents(); it displays data after page reload.
  • Iancovici
    Iancovici over 6 years
    @Adriano check your rxjs in package.json, and let me know what version it is. Also do you see any errors when inspecting page?
  • Adriano
    Adriano over 6 years
    @lancovici it's "rxjs": "^5.5.2", No I didn't notice any errors. I make subscibing works but only after I add a next 'Event'
  • Iancovici
    Iancovici over 6 years
    @Adriano, Not sure how you are setup right now, maybe put it in stackblitz.com. in this example I'm showing you how to get the list on initialization from a service, then whenever someone update the list, the service updates list, then calls next on subject, and inputs the list. The component that needs to listen, will have to get the list inside its subscription callback.
  • Adriano
    Adriano over 6 years