I have two components that inject the same service. One component needs to function independently of the other component, but may be be added to the other component at any time, and both components need the same data. I want to avoid the data being loaded twice (i.e, just load it once regardless of which component requested the data).
The shared service:
@Injectable()
export class UserDetailsService {
private userDetailsSubject: BehaviorSubject<UserDetails> = new BehaviorSubject<UserDetails>(new UserDetails());
public currentModel: Observable<UserDetails> = this.userDetailsSubject.asObservable();
constructor(private userDetailsRepository: UserDetailsRepository) {}
public loadUserDetails(id: string) {
// loadUserDetails makes a HttpClient get call which returns the result as an Observable
this.userDetailsRepository.loadUserDetails(id)
.subscribe(details => this.userDetailsSubject.next(details));
}
}
The first component:
export class UserLookupComponent implements OnInit {
// Other logic ...
// The user is loaded via lookup.
public user: User;
constructor(private detailsService: UserDetailsService) {}
public loadUserDetails() {
this.detailsService.loadUserDetails(user.id);
}
ngOnInit() {
this.detailsService.currentModel.subscribe(details => {
this.user.details = details;
});
}
// Other logic...
}
The second component is virtually identical to the first component, with different other logic relevant to its purpose. It's basically an Overview component which should get the details for the user if they're not already loaded using this.detailsService.loadUserDetails(user.id)
, and setting the user's details using this.detailsService.currentModel.subscribe...
exactly the same way the first component does.
The issue however is that the data is being requested twice, and I want to avoid this behavior and only load the data once. I have tried setting the subject to a Subject<string>
, and adding a debounceTime
and mergeMap(id => this.userDetailsRepository.loadUserDetails(id))
to the currentModel, but the same thing happens. How can I only retrieve the details once?
I should also note that the User is being retrieved and set using another Service. This service is also shared between both components (so they can both get the same user).
Edited based on below comments
If you can initialize userDetailsSubject as null...
In Component 1, call loadUserDetails in ngOnInit after your subscription to currentModel. Service...
public loadUserDetails(id: string) {
this.userDetailsSubject.next(new UserDetails())
this.userDetailsRepository.loadUserDetails(id)
.subscribe(details => this.userDetailsSubject.next(details));
}
Component 2... in ngOnInit...
this.detailsService.currentModel.subscribe(details => {
if (!details) this.loadUserDetails();
else this.user.details = details;
});