0

I have a service: ScheduleService that holds a ReplaySubject<Shift>:

private readonly shiftSubject = new ReplaySubject<Shift>();

I expose this subject to consumers via this method:

currentShift(): Observable<Shift> {
        return this.shiftSubject.asObservable();
}

It's my intention that a new Shift value can be pushed into the shiftSubject via this method:

updateShift(shift: Shift) {
        console.log('updating shift: ' + shift.shiftName); // I AM SEEING THIS LOG
        this.shiftSubject.next(shift); // I'VE VERIFIED THAT THIS VALUE IS BEING UPDATED
}

However, it does not appear that subscribers to currentShift() are receiving new emissions when this.shiftSubject.next(shift) is called. I have bound the value of this subject to a mat-select component like this:

<mat-select [formControl]="shiftSelect" (selectionChange)="updateShift($event)" [value]="(scheduleService.currentShift() | async)">
        <mat-option *ngFor="let shift of (scheduleService.availableShifts() | async)" [value]="shift">
            {{shift.shiftName | titlecase}}
        </mat-option>
</mat-select>

...and I've also subscribed in the consuming component like this, just for debugging:

export class ShiftSelectorComponent implements OnInit, OnDestroy {

    shiftSelect: FormControl;

    constructor(private scheduleService: ScheduleService) {
        this.shiftSelect = new FormControl();
    }
    ngOnInit() {
        this.scheduleService.currentShift().subscribe((shift) => console.log('SHFIT SELECTOR RECEIVES NEW SHIFT: ' + shift.shiftName));
    }
    ...

Nothing I try seems to cause subscribers to this subject to receive updates. I can't figure out what I'm doing wrong. I have double checked that the service is a singleton, as other posts have mentioned that. The ScheduleService is provided to consumers in app.module.ts.

Thanks.

FerdTurgusen
  • 320
  • 5
  • 13
  • is `ScheduleService` provided by shared module? – Rafi Henig Aug 23 '20 at 19:29
  • @Rafi Henig it’s provided in the app.module.ts, which is the topmost module in my application. I’ve also tried making it root level by doing `Injectable(providedIn: ‘root’)` but to no avail. – FerdTurgusen Aug 23 '20 at 19:47
  • @NathanQuirk can you add `updateShift` method (in your controller) to question ? – yaya Aug 23 '20 at 19:51
  • trying assign `scheduleService.availableShifts()` to property, something like this: `shifts$ = scheduleService.availableShifts()` and in template: `*ngFor="let shift of (shift$ | async)"` – Petrus Nguyễn Thái Học Aug 23 '20 at 20:01
  • is `ShiftSelectorComponent` declared by app module as well? – Rafi Henig Aug 23 '20 at 20:17
  • you have couple of issues in your code. here is a fixed code : https://stackblitz.com/edit/angular-material-vts2rp?devtoolsheight=33&file=app/schedule.service.ts – yaya Aug 23 '20 at 21:01
  • also note that most probably the reason you're not receiving the observable changes is not the problem you mentioned (listeners don't get the updates). instead it's because your component is buggy (so it can't submit the change or it's on infinite ui loop so it can't log the updates.). just remove any instance of `` from your app (cause it's buggy), create another empty component, and in that component create a button to change the current value on click, and subscribe to the observable on init. (don't add any ui). you'll most probably see that it works. – yaya Aug 23 '20 at 21:14

1 Answers1

0

You really shouldn't expose your service as a public and expose it in the template, everytime change detection runs you create another observable.

in your component create the observables

currentShift$ = this.scheduleService.currentShift();
availableShifts$ = this.scheduleService.availableShifts();

and then use that in the template.

<mat-select [formControl]="shiftSelect" (selectionChange)="updateShift($event)" [value]="currentShift$ | async">
        <mat-option *ngFor="let shift of (availableShifts$ | async)" [value]="shift">
            {{shift.shiftName | titlecase}}
        </mat-option>
</mat-select>
Adrian Brand
  • 20,384
  • 4
  • 39
  • 60