1

In my app, I have a UserService that fetches a user object from an API.

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

@Injectable()
export class UserService {
    constructor() {
        this.userSource.subscribe(user => console.log(user));
    }

    user:any = {
        name: 'Lindsey Buckingham'
    };
    private userSource = new BehaviorSubject<any>(this.user);
    user$ = this.userSource.asObservable();

    // fetch user data from HTTP and call 'next()' on observable
}

Then I have multiple components consuming this service. For example, a profile page:

import { Component } from '@angular/core';

import { UserService } from '../shared/user.service';

@Component({
    selector: 'profile',
    templateUrl: './profile.component.html'
})
export class ProfileComponent {
    constructor(private userService:UserService) {}

    private user:any = {};

    ngOnInit() {
        this.userService.user$.subscribe((user) => this.user = user);
    }
}

Now the issue I'm having is this: if in my profile component I edit the user object, the change immediately propagates everywhere, so all components immediately receive the updated object. I was under the impression that by subscribing to the stream from the UserService, I would create a local copy and if I wanted to update the user object in my components, I'd use a method on the UserService that calls this.user$.next() and only then the user object in my components would change, as well. But, apparently not.

Getting the hang of observables, but it seems I'm not quite there yet. Could anyone explain to me where I'm going wrong?

Update:

Creating a local copy of the observed object indeed does do the trick.

ngOnInit() {
    this.userService.user$.subscribe((user) => {
        let localUser = _.merge({}, user); 
        this.user = localUser;
    });
}
Brother Woodrow
  • 6,092
  • 3
  • 18
  • 20

1 Answers1

1

The observable just passes the object reference along. If you modify properties of this object, then everyone that has a reference to this same object instance sees this change. Only with primitive values copies are sent. It's the same as with function calls and actually that exactly what observables do (as any TypeScript or JS code)

You need to create a copy yourself if you don't want to work with copies, or you change the code that emits values to create a copy before sending the event.

See also typescript - cloning object

Community
  • 1
  • 1
Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
  • Got it. So really, not much has changed over the years :P I know JavaScript has worked this way for years (passing objects by reference) but I thought observables would be different, for some reason. – Brother Woodrow Oct 06 '16 at 08:39
  • Observables are just just classes and methods/functions written in TypeScript that gets transpiled to JS. And no, nothing has changed :D – Günter Zöchbauer Oct 06 '16 at 08:44
  • 1
    `Observable` was created to solve another problem. What you are looking for may be this: https://facebook.github.io/immutable-js/ – Harry Ninh Oct 06 '16 at 08:54