We are trying to use an angular pipe to filter a list of sub items, (if no items then parent item is removed)
HTML :-
<div class="row border-bottom item" *ngFor="let item of pageContent | filter: searchText; let i = index">
<div class="col-6">{{item.name}}</div>
<div class="col-6">
<ul>
<li *ngFor="let link of item.content">
{{link.content}}
</li>
</ul>
</div>
</div>
our pipe is like this :-
export class FilterPipe implements PipeTransform {
transform(items: AllContent[], searchText: string): AllContent[] {
if (!items) return [];
if (!searchText) return items;
return items.filter(item => {
item.content.filter(c => c.content.toLowerCase().includes(searchText.toLowerCase()))
})
we cannot get this filter to work and it literally not filtering the the child items out.
we have also tried
return items.foreach(item => {
item.content.filter(c => c.content.toLowerCase().includes(searchText.toLowerCase()))
})
is there somthing that we are missing?
2
Answers
You’re missing a
return
statement in the filter method and you need to add.length
:When it’s a one-liner, you don’t need the
return
, but when breaking it to multiple lines using the{...}
, then you need to return the items. Same witharray.map()
.What @Adam Jenkins mentions in the comment is important to note. The condition in an
array.filter()
method needs to return eithertrue
orfalse
(or a truthy or falsey value). The nested.filter()
(on the inside) however returns an array, which is always truthy. This means the outside.filter()
method, and therefore the pipe, will always return all of the items. To get around this you could add.length
at the end of the nestedfilter()
method. This will return a number based on how many items are included in the array returned by the nested.filter()
. If it has 1 or more items, the condition will be truthy and the pipe will return the pageItems that has content that includes the searched text. If the nestedfilter()
returns 0 items in its array, the condition will be falsey, in which case the pipe will not return that pageItem.Another solution could be to use the
.some()
method, which returnstrue
orfalse
. This array stops when it hits true, in which case it won’t have to continue iterating over the rest of the items. This is better for performance.If you want to filter both the pageItem and content of the pageItem then you could do the following (assuming the pipe resets the items when filtering. Not sure if it does.):
Also, the way it’s written it looks like an item has a property of
content
which has a property ofcontent
inside it. Not sure if this is what you intended, but this code is assuming that that is correct.The problem lies in how you’re using the filter function. The filter function creates a new array with all elements that pass the test implemented by the provided function. However, in your current implementation, you’re using filter on the parent item, but not returning the result of this operation.
Here’s the corrected version of your custom pipe: