There are two rather different approaches you could take:
1. Share data via JavaScript reference types
If you create an object in your UserService
@Injectable()
export class UserService {
public user = new User();
you can then share that object just by virtue of it being a JavaScript reference type. Any other service or component that injects the UserService will have access to that user
object. As long as you only modify the original object (i.e., you don't assign a new object) in your service,
updateUser(user:User) {
this.user.firstName = user.firstName;
this.user.lastName = user.lastName;
}
all of your views will automatically update and show the new data after it is changed (because of the way Angular change detection works). There is no need for any Angular 1-like watchers.
Here's an example plunker.
In the plunker, instead of a shared user
object, it has a shared data
object. There is a change data button that you can click that will call a changeData()
method on the service. You can see that the AppComponent's view automatically updates when the service changes its data
property. You don't have to write any code to make this work -- no getter, setter, Input, Output/EventEmitter, or Observable is required.
The view update automatically happens because (by default) Angular change detection checks all of the template bindings (like {{data.prop1}}
) each time a monkey-patched asynchronous event fires (such as a button click).
2. "Push" data using RxJS
@HarryNinh covered this pretty well in his answer. See also Cookbook topic Parent and children communicate via a service. It shows how to use a Subject to facilitate communications "within a family".
I would suggest using a BehaviorSubject instead of a Subject because a BehaviorSubject has the notion of "the current value", which is likely applicable here. Consider, if you use routing and (based on some user action) you move to a new route and create a new component, you might want that new component to be able check the "current value" of the user. You'll need a BehaviorSubject to make that work. If you use a regular Subject, the new component will have no way to retrieve the current value, since subscribers to a Subject can only get newly emitted values.
So, should we use approach 1. or 2.? As usual, "it depends". Approach 1. is a lot less code, and you don't need to understand RxJS (but you do need to understand JavaScript reference types). Approach 2. is all the rage these days.
Approach 2. could also be more efficient than 1., but because Angular's default change detection strategy is to "check all components", you would need to use the OnPush
change detection strategy and markForCheck()
(I'm not going to get into how to use those here) to make it more efficient than approach 1.