Mark
Mark

Reputation: 44

Angular2 Component subscription incorrect implementation

I have a general understanding of how Angular2/RXJS observables work when they are subscribed to but I'm making a mistake somewhere.

In my service I have an observable available like so:

    // Source
    private objectDetailsCache = new Subject<ObectDetails>();
    // Stream
    public objectDetails$ = this.objectDetailsCache.asObservable().cache();

The service manipulates the observable with these methods:

    updateObject(object: ObjectDetails): Observable<ObjectDetails> {

    let objectMapped = this.mappingService.mapObjectDetailsToObject(object);

    this._HTTPService.update(this._objectUrl + object.id, objectMapped)
        .subscribe(o => {
            this.objectDetailsCache.next(o);
        });
    return this.objectDetails$.last();
    }

    getObjectDetails(id: number): Observable<ObjectDetails> {
    this._HTTPService.get(this._objectUrl + id + '/details')
        .subscribe(o => {
            this.objectDetailsCache.next(o);
        })
    return this.objectDetails$.last();
    }

I have a parent component that subscribes to the observable and tracks the changes made to it by its children

    constructor(private objectService: ObjectService) {
    objectService.objectDetails$.subscribe(o => this.object = o);
}

Then the component tells the app which object it wants observing:

    ngOnInit() {
        this.loadObjectDetails();
    }

    loadObjectDetails() {
        this.sub = this.route.params.subscribe(params => {
            let id = +params['id'];
            this.objectService.getObjectDetails(id)
                .subscribe(
                o => {  },
                error => { });
        });
     }

This so far is all okay. The problem comes when the child components subscribe to the parent's object observable:

    ngOnInit() {
       this.sub = this.objectService.objectDetails$.subscribe(
            o => {
                this.object = o;
                this.getHeaders()
            }
       );
    }

    ngOnDestroy(){
        this.sub.unsubscribe();
    }

When the parent changes the object it is observing, the child is hit with every object that has been observed previously instead of just the last one. So in this child's case if the parent has observed 3 objects this.getHeaders() is called 3 times when the child subscribes.

I've tried moving the child methods to the complete part of the subscription:

() => this.getHeaders()

but it never gets hit.

I've tried putting the parent subscription in ngOnInit() and unsubscribing in ngDestroy() but it fails to subscribe to anything like that.

Any suggestions about how I can adjust how I go about this would be great.

I hope this makes sense, Thanks in advance.

Upvotes: 1

Views: 235

Answers (1)

Mark
Mark

Reputation: 44

I was able to get round the issue using BehviourSubject from the RXJS library:

https://xgrommx.github.io/rx-book/content/subjects/behavior_subject/index.html

specifically the .getValue() member returns the last object in the observable stream. So instead of having the child components subscribe to the observable they just ask for the latest value. This way when they update the observable steam they don't recycle themselves.

Upvotes: 0

Related Questions