I'm trying to use an ngrx selector that takes a property of jobId to return some data as an observable.
I'm first loading all of the jobs and tasks from a database but they don't come back in time for the selectors and I get an error because this.task is undefined, which I believe is keeping the observable from running again.
Is there a way to wait for the data to return before the selectors try to fetch the data from the store?
this.store.dispatch(fromTasks.loadAllTasks());
this.store.dispatch(fromJobs.loadAllJobs());
taskSubscription$ = this.store.pipe(
select(fromTask.getSelectedTask),
tap(task => this.task = task)).subscribe()
jobSubscription$ = this.store.pipe(
select(fromJob.getJobById, {jobId: this.task.jobId}),
tap(job => this.job = job)).subscribe();
Here is an approach you can consider :
1) Selector getSelectedTask
return null
if no selected task
export const getSelectedTask = createSelector(
selectEntities,
getSelectedTaskId,
(entities: Dictionary<Task>, selectedId: number) => {
return selectedId ? entities[selectedId] : null;
}
)
2) Use async
pipe and *ngIf
inside template
Component.ts
@Component({
selector: 'my-component',
...
})
export class MyComponent {
selectedTask$ = this.store.pipe(select(getSelectedTask));
...
}
Template.html
<ng-container *ngIf="selectedTask$ | async as selectedTask else noSelection">
<my-task [task]="selectedTask"></my-task>
// or
<span>{{ selectedTask.description }}</span>
</ng-container>
<ng-template #noSelection>
Please select a task !
</ng-template>
With this approach, you will use the powerful of observables with angular template syntax.
If user unselect current task, getSelectedTask
selector will return null
and template will be automatically updated.
Nevertheless, you can continue to use subscription
, but in this case, prefer to set the value inside subscribe
method and be sure to unsubscribe.
@Component({
selector: 'my-component',
...
})
export class MyComponent implements OnInit, OnDestroy {
subscription: Subscription;
selectedTask$ = this.store.pipe(select(getSelectedTask));
selectedTask: Task;
constructor(
private store: Store<AppState>
) { }
ngOnInit() {
this.subscription = this.selectedTask$.subscribe(task
=> this.selectedTask = task);
}
ngOnDestroy() {
this.subscription.unsubscribe();
}
}