I would like to know how the setFilter method works for the EntityCollectionService in @ngrx/data. The documentation hints at how it is used, but there is no example showing the actual setFilter(pattern: any) function being used. Since the argument can be of type any, I cannot really infer what should be done here.
Basically, I have a list of objects in the data store using the @ngrx/data module. I would like to define a filter so that I can subscribe to the filteredEntities$ observable of the EntityCollectionService. I can successfully subscribe to the entities$ observable and receive the full unfiltered list. Previously, I was doing the filtering outside of the EntityCollectionService, but I would like to utilize the built-in filtering mechanism.
export class MyComponent implements OnInit {
filteredProjects$: Observable<Project[]>;
typeFilterOptions: FilterOption[];
stageFilterOptions: FilterOption[];
constructor(private projectService: ProjectEntityService, ptivate metadataService: MetadataService) {}
ngOnInit() {
this.typeFilterOptions = this.metadataService.getProjectTypes();
this.stageFilterOptions = this.metadataService.getProjectStages();
this.filteredProjects$ = this.projectService.filteredEntities$;
}
onFilterChange() {
typeFilter = typeFilterOptions.filter(option => option.isChecked).map(option.name);
stageFilter = stageFilterOptions.filter(option => option.isChecked).map(option.name);
this.projectService.setFilter(project => {
return (typeFilter.indexOf(project.type) >= 0) &&
(stageFilter.indexOf(project.stage) >= 0);
}
}
}
The above code is my best approach at trying to set the filter correctly. Obviously, that is not working as I expected it would. When setting the filter to a filter function nothing changes even though I can see the set filter
action firing as expected. The entities are still not being filtered at that point. The argument being label as pattern: any
make me think that it should be something other than a function, but again I cannot infer off of the documentation what it is expecting.
Ok so digging into the source code I was able to figure out how to use the filter on an ngrx/data Entity Service.
The piece I was missing was defining the filter function in the Entity Service metadata configuration (see docs here):
app.module.ts
const entityMetadata: EntityMetadataMap = {
Project: {
//pattern can be any object you want it to be. This is the same argument used in setFilter(pattern: any)
filterFn: (entities: Project[], pattern: {types: string[], stages: string[]}) => {
return entitites.filter(entity => {
return (pattern.types.indexOf(entity.type) >= 0) &&
(pattern.stages.indexOf(entity.stage) >= 0)
});
}
}
};
@NgModule({
...
})
export class AppModule {
constructor(private eds: EntityDefinitionService) {
eds.registerMetadataMap(entityMetadata);
}
}
then in the component all you need to do is create the filter object and use it as the argument to setFilter on the Entity Service:
my.component.ts
export class MyComponent implements OnInit {
filteredProjects$: Observable<Project[]>;
typeFilterOptions: FilterOption[];
stageFilterOptions: FilterOption[];
constructor(private projectService: ProjectEntityService, private metadataService: MetadataService) {}
ngOnInit() {
this.typeFilterOptions = this.metadataService.getProjectTypes();
this.stageFilterOptions = this.metadataService.getProjectStages();
this.filteredProjects$ = this.projectService.filteredEntities$;
}
onFilterChange() {
typeFilter = typeFilterOptions.filter(option => option.isChecked).map(option.name);
stageFilter = stageFilterOptions.filter(option => option.isChecked).map(option.name);
this.projectService.setFilter({
types: typeFilter,
stages: stageFilter
});
}
}
At this point anything in your template subscribed to the filteredProjects$ observable will get the update filtered entities when setFilter is called. For example:
my.component.html
...
<app-project-list [projects]="filteredProjects$ | async"></app-project-list>
...