Reputation: 8336
I have redux state in angular app:
export interface UIAction {
name: string;
isActive: boolean;
}
export interface IUIState {
actions: UIAction[];
}
I have built an angular service that subscribes to the state and stores Subjects for each action in a Map and returns that subject for callers that are interested in isActive-value for a certain action. It's something like this:
public getIsActive$(name: string): Observable<boolean> {
let sub = this.subsMap.get(name);
return sub.asObservable();
}
Now I want to change the code and get rid of the Map with all the Subjects and do something like this:
public getIsActive$(name: string): Observable<boolean> {
return this.ngRedux.select<IUIState>('ui').pipe(
/* this should use some operators so that
the returned Observable emits only when
UIAction.isActive changes for the action
in question. The action in question is
found from the state.actions-array using
parameter 'name' */
)));
}
How this should be done? Below an example.
Initially the UIState.actions looks like this:
[ { name: 'Save', isActive: false }, { name: 'Cancel', isActive: true } ]
At this point I call
myService.getIsActive$('Save').subscribe(isActive => {
console.log('Value : ${isActive});
});
then I dispatch a redux state change (only new values here):
{ name: 'Cancel', isActive: false }
The UIState.actions changes to:
[ { name: 'Save', isActive: false }, { name: 'Cancel', isActive: false} ]
The subscription however does not write to console because it wasn't subscribed to changes of 'Cancel' action.
Then I dispatch another redux state change (only values here):
{ name: 'Save', isActive: true }
And the UIState.actions changes to:
[ { name: 'Save', isActive: true}, { name: 'Cancel', isActive: false} ]
Now the subscription writes to console:
Value: true
because it was subscribed to changes of 'Save' action.
Upvotes: 1
Views: 2617
Reputation: 8336
If someone is interested in this, I did it like this. Thanks for others pointing me to right direction:
public getIsActive$(name: UIActionName): Observable<boolean> {
return this.getUIAction$(name).pipe(
map(axn => axn.isActive)).pipe(distinctUntilChanged());
}
private getUIAction$(name: UIActionName): Observable<UIAction> {
return this.ngRedux.select<IUIState>('ui').pipe(map(state => {
return state.actions.find(actn => actn.name === name);
})).pipe(
filter((axn: UIAction | undefined): axn is UIAction => axn !== undefined));
}
Upvotes: 0
Reputation: 1852
Hopefully I'm understanding this requirement correctly. You can apply a custom function to distinctUntilChanged()
for more complex cases.
public getIsActive$(name: string):Observable<boolean> {
return this.ngRedux.select<IUIState>('ui').pipe(
map(uiState=>uiState.find(state=>state.name===name)),
filter(state=>!!state),
distinctUntilChanged((prev, curr)=>
prev.name===curr.name && prev.isActive === curr.isActive
),
map(state=>state.isActive)
);
}
Here's a line-by-line of what's going on:
.find()
returns undefined
name
and isActive
. If either property doesn't match its previous value, it will emit the new value.isActive
boolean.Upvotes: 2