connor.roche
connor.roche

Reputation: 55

Angular7 - reference property in service or subscibe to it

I have a service with a property in it that I want to refer to and change in multiple components. Can I just reference it directly in my components by assigning it to a property in the component or should I subscribe to an observable? I tried it both ways and when I modify it in the component both ways seem to change the property in the service.

account.service.ts

export class AccountService {

constructor(private http: HttpClient) { }

testAccount: Account = {
    domain_name: "fortestaccoutnpage2",
    account_number: "fortestaccoutnpage2",
    bill_timing: "anniversary",
    }

getAccount(): Observable<Account> {
    return of(this.testAccount);
}

}

account.component.ts

export class AccountComponent implements OnInit {

constructor(private _accountService: AccountService) { }

changeAccountNumber() {
    this.account.account_number = "changed"
}

account: Account = this._accountService.testAccount;

grabAccount(): void {
    this._accountService.getAccount()
        .subscribe(account => this.account = account);
}

ngOnInit() {
    //this.grabAccount();
}

}

Is the above example I basically have account in the component refer to the testAccount in the service and the changeAccountNumber method works. I commented out the method to have account subscribe to the observable, but when I do it that way it works as well. Is one way better than the other or are both fine?

Upvotes: 1

Views: 52

Answers (3)

Rabindranath ferreira
Rabindranath ferreira

Reputation: 112

Use behavior Subject implementation from Rxjs, declare un your service and instace a behavior subject, after create another variable asObserver, them you must use the next method on behaviors subject implementations using in your component of interest for send last changes to your Behavior Subject in your service and later you can subscribe in any component U wanted the info

check this firts https://medium.com/@luukgruijs/understanding-rxjs-behaviorsubject-replaysubject-and-asyncsubject-8cc061f1cfc0

and this http://reactivex.io/rxjs/manual/overview.html

try something and after i can help U better

Upvotes: 0

bgraham
bgraham

Reputation: 1997

It's probably better to subscribe, instead of reference directly from the service.

The advantage of subscribe is that call will only be fired when the observable is called. So in this case it doesn't really matter, because you are just using a test object. But if you were calling from a server, you couldn't be sure when your data comes back. So if you clicked the button before the data came back, things could go south.

Additionally, currently you aren't doing anything except for assigning the account to a property. Which is valid. But if later you want to do something else, like have a loading spinner, and turn it off when you get the data. You would need to take advantage of the observable for sure.

Edit: Also, its probably not great practice to alter the account inside the component itself. That would work for sure, but it can lead to some confusing bugs and make things harder to test if you go that route. Its better for changes to be centralized. I would recommend adding a method to the service for changeAccountNumber(newNumber), and that service would push out a new observable with the changed account value. Kind of fancy, but its a lot more testable and I would argue more maintainable.

Upvotes: 3

displayName
displayName

Reputation: 1106

grabAccount(): void {
    this._accountService.getAccount()
        .subscribe(account => this.account = account);
}

here you are assigning value of account (which is _accountService.testAccount) to this.account. So this.account and _accountService.testAccount are references to the same object in memory. Changing one is always going to affect the other.

To avoid this you can simply clone the object before assigning it to this.account

Here is a simple way to do this:

grabAccount(): void {
    this._accountService.getAccount()
        .subscribe(account => this.account = JSON.parse(JSON.stringify(account)));
}

Or to avoid code duplication, you can clone in the service

getAccount(): Observable<Account> {
    return of(JSON.parse(JSON.stringify(this.testAccount)));
}

This cloning method won't work if you have more complex objects (with Date values for example)

How do I correctly clone a JavaScript object?

Upvotes: 0

Related Questions