I have a component where I display table of tasks. Since the amount of tasks may grow huge after time I decided to use textfield with autocomplete as an alternative to just scrolling. The idea is that you:
- Type task name and pick one you looked for.
- The table is refreshed and now displays only one element - chosen task. Now in code:
- Click method on dropdown, which takes a whole list, filters it and overwrites the observable with task selected.
- List is refreshed and displayed.
component.html
<mat-autocomplete #auto="matAutocomplete">
<mat-option *ngFor="let task of myTasks$ | async" (click)="selectSingleTask(task.taskId)"
[value]="task.taskId">
{{task.taskId}}
</mat-option>ł
</mat-autocomplete>
component.ts
selectSingleTask(taskID: string) {
return this.myTasks$.subscribe(tasks => tasks.filter(task => task.taskId === taskID));
}
How can I update the list and refresh it on front? Let me know if there is some topic I should read about or expand my knowledge to solve this problem.
Thanks
CodePudding user response:
That's the way I usually do it:
class YourComponent {
myTasks$; // whatever is your current definition
selectedTaskId$ = new ReplaySubject<string | null>(null)
myFilteredTasks$ = combineLatest([ this.myTasks$, this.selectedTaskId$ ]).pipe(
map(([ list, selectedId ]) => !selectedId ? list : list.filter(({ id }) => id === selectedId))
)
}
And in your template:
<mat-autocomplete #auto="matAutocomplete">
<mat-option *ngFor="let task of myFilteredTasks$ | async" (click)="selectedTaskId$.emit(task.taskId)"
[value]="task.taskId">
{{task.taskId}}
</mat-option>ł
</mat-autocomplete>
This is a rough example, you might need to add some share()
/shareReplay()
etc. in case you use the list in several places, a way to reset value, and maybe something else.
Main idea is: you have streams of data and events, and you mix them to get modified streams with properties you need. In this particular case, you have all items, and selected item ID, and you produce stream of, well, array with single item with that ID (having a search box instead could be more useful, or you can have both).
CodePudding user response:
There are multiple approaches. This is probably the easiest one: add a new property to your component to store the selected task and update it in the selectSingleTask function.
component.ts
private selectedTask$$: Subject<Task> = new BehaviorSubject<Task | undefined>(undefined);
selectedTask$ = this.selectedTask$$.asObservable(); // best practice: don't expose the subject itself
selectSingleTask(task: Task) {
return this.selectedTask$$.next(task);
}
component.html
<p>(Test output) Selected task: <pre>{{ selectedTask$ | async | json }}</pre>