Using Angular's filter pipe to search within a nested array

We are attempting to implement an angular pipe for filtering a list of sub-items, with the goal of removing parent items if there are no child items present. Here is the HTML code snippet we are using:

   <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>

This is how our pipe is defined:

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 have been unable to successfully filter out the child items. We have also attempted the following approach:

return items.foreach(item => {
item.content.filter(c => c.content.toLowerCase().includes(searchText.toLowerCase()))
})

Is there something that we might be overlooking or missing in our implementation?

Answer №1

The filter method is missing a crucial return statement and you must remember to include .length:

return items.filter(item => {
  // make sure to add the return keyword and append .length at the end
  return item.content.filter(c => c.content.toLowerCase().includes(searchText.toLowerCase())).length
})

For one-liners, there's no need for the return keyword, but when splitting into multiple lines with curly braces {...}, you must explicitly return the items. This also applies to array.map().

Note @Adam Jenkins' comment: The condition in an array.filter() method should evaluate to either true or false (or something truthy/falsey). The inner nested .filter() always returns an array which is truthy, causing the outer .filter() to return all items. To fix this, appending .length after the nested filter() will ensure it evaluates correctly. A better alternative could be utilizing .some() for improved performance.

If filtering both the pageItem and its content, consider the following approach (assuming pipeline resets items on filter):

items = items.filter(item => {
    item.content = item.content.filter(c => c.content.includes(searchText))
    return item.content.length ? true : false
})
return items

Also worth noting, based on current structure, it seems like an item contains a property named content which itself has a property of content. Confirm if this aligns with your intended design.

Answer №2

The issue stems from how you've implemented the filter function. When using the filter function, a new array is generated with elements that meet the criteria set by the provided function. However, in your current setup, you are applying the filter to the parent item without returning the outcome of this operation.

Below is the revised version of your custom pipe:

import { Pipe, PipeTransform } from '@angular/core';
@Pipe({
    name: 'filter'
})
export class FilterPipe implements PipeTransform {
    transform(items: AllContent[], searchText: string): AllContent[] {
        if (!items) return [];
        if (!searchText) return items;
        return items.filter(item => {
            item.content = item.content.filter(c => c.content.toLowerCase().includes(searchText.toLowerCase()));
            return item.content.length > 0; // Exclude parent items without matching sub-items
        });
    }
}

Answer №3

Utilize the map function to filter out elements in an array and create a new array of filtered items.

export class FilterPipe implements PipeTransform {
  transform(items: AllContent[], searchText: string): AllContent[] {
    if (!items) return [];
    if (!searchText) return items;

    return items
      .map(item => { // Use map to transform each item
        return {
          ...item,
          content: item.content.filter(c => c.content.toLowerCase().includes(searchText.toLowerCase()))
        };
      })
      .filter(item => item.content.length > 0); // Use filter to remove items with no content
  }
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Tips for handling a variable that could potentially be an array or a single React component

I'm diving into React for the first time and working on creating a user survey. I'm currently dealing with checkboxes in this component, which I find a bit challenging. My goal is to have the user select 2 options and then separate them with a co ...

Scrolling back to the top of the page using Jquery instead of a specific div

Check out the code for my project here. The isotope feature is functioning correctly, however, when clicking on the image, instead of scrolling to the navigation under the red box as intended, the page scrolls all the way to the top. If I modify the follo ...

Optimizing Backend Access with Laravel and Vue JS: How to Choose the Most Effective Approach

Currently, I am utilizing Laravel API passport to handle authentication in my Single Page Application (SPA) built with Vue. At the moment, whenever I need to access the backend server, I have to include a header in order to be allowed through the protected ...

Angular 5 Image Upload - Transfer your images with ease

I am having trouble saving a simple post in firebase, especially with the image included. This is my current service implementation: uploadAndSave(item: any) { let post = { $key: item.key, title: item.title, description: item.description, url: '&a ...

Resolving the Table Issue with 'onclick' in Javascript

Apologies for the lack of creativity in the title, I struggled to come up with something fitting. Currently, I am engaged in the development of a user-friendly WYSIWYG site builder. However, I have encountered an obstacle along the way. I've devised ...

The mysterious case of TypeScript imports making all other code vanish

I have multiple classes located in root/app/providers/engine/engine.ts. In my test specification file spec/engine/engine-spec.ts (the spec/ directory is also where the jasmine support/ resides), I have a simple test: ///<reference path="../../typings/g ...

The functionality of router.navigate in Angular 5 seems to be malfunctioning

I am struggling with redirecting a user to another page based on a certain condition. Here is an example of my login component: ngOnInit() { console.log(">>> router", this.router) console.log(">>> activatedRoute", this.activate ...

Dynamic, AJAX-driven content is experiencing a 200 status code

Is it necessary for a single-page website, which dynamically loads content via ajax and utilizes browser session history stacking, to return a "200 Status" for each successful state change? The core code of my website is as follows: $(document).on('c ...

Is there a method to use media queries to dynamically switch JavaScript files based on the user's device?

I've been working on optimizing the mobile layout of my website, and while I have successfully implemented a media query with a different stylesheet for mobile devices, I'm struggling to determine if it's feasible to also load a separate Jav ...

The style attribute is triggering an error stating that 'Every child in a list must possess a distinct "key" property.'

Can anyone explain why I'm encountering an error when storing JSX code in a variable like this? const centerStyle = {textAlign: 'center'}; viewState.myContent = ( <Fragment> <p style={centerStyle}>Some text</p> < ...

The validations continue to function properly even when HTML has been removed

In my form, I have implemented an "addmore" functionality that allows users to dynamically add a set of HTML input fields. Users can also remove the added rows if needed. While everything is functioning correctly, I am encountering an issue where validatio ...

Using Angular's [ngIf], [ngIfElse], and [ngIfElseIf] functionalities enables dynamic content rendering

Currently, I have the following code snippet: <ng-container *ngIf="someCondition"> <ng-template [ngIf]="cd.typedType === 'first'" [ngIfElse]="Second"> <div class="row"> fir ...

Three.js fails to load due to Require.js issue

Having encountered a JavaScript error in browser (on the last line mentioned above) with generated code from TypeScript: define(["require", "exports", "three", "jquery", "./test"], function (require, exports, THREE, jQuery, Test) { var Main = (function () ...

Alert displaying NextJS props

I recently began learning Next.js and have encountered an issue while trying to pass props from a parent component to a child component. The error message I'm seeing is: Type '({ name }: { name: any; }) => JSX.Element' is not assignable ...

Testing Ag Grid's column headers using Jest and Angular CLI has proven challenging, as some columns from columnDefs remain elusive

Currently, I am using Jest and Angular Cli testing to validate column headers. In my attempt to replicate the process outlined on https://www.ag-grid.com/javascript-grid-testing-angular/#testing-grid-contents, I have encountered an issue where only 2 out ...

Issue encountered while rendering tables with Jquery-dataTables

Encountering an issue with jquery datatables when fetching data from a URL using ajax calls. Implementing the codeigniter framework, I utilize the datatables library to create datatable objects by invoking the echo $this->datatables->generate() metho ...

Receive regular updates every week for an entire month using Javascript

How can I calculate the number of check-ins per week in a month using Javascript? I have been unable to find relevant code for this task. Specifically, I am interested in determining the total count of user check-ins on a weekly basis. For example, if a u ...

Utilizing NextJS to retrieve cookie data within React components

Currently, I am working with a Next.js frontend and an Express backend. For authentication, I am utilizing cookies and have set up protected routes using Next.js middleware. The next step in my project involves accessing the cookie response within React ...

The back-to-top button guides users back to their last visited page

I'm excited to explore AngularJS and I want to add two "return to top" buttons on different pages. Here's what I have so far: Page 1: <h1 id = "top"> .......... <a href="#top" target = "_self">Return to Top</a> Page ...

How can I prevent the <br/> tag from being included on every new line when exporting data to PDF in jQuery Datatable?

I am currently working with a datatable that contains a large amount of data. Within this table, I have included 2 buttons for exporting the data in PDF and CSV formats. One of the columns within my table contains a comma-separated string, and when I expor ...