Angular Pipe displays values properly, but ngFor fails to render them

I am using a pipe to filter my ngFor loop with exact matches that are passed through by clicking on the filter argument.

Below is the code for my pipe:


        transform(values: any[], criteria: string, group): any[] {
            if (!values) {
              return [];
            }
            if (!group || group.length === 0) {
              return values;
            }
            return values.filter(item => item[criteria] === group);
          }
    

Here is how I'm implementing it in HTML:


        <mat-drawer-container class="example-container">
          <mat-drawer mode="side" opened class="side-nav">
            <div *ngFor="let skillGroup of skillGroups | unique:'skillGroup'">
              <button mat-button class="filter">
                <div (click)="filterSkills(filter.textContent)" #filter>
                  {{ skillGroup.skillGroup }}
                </div>
              </button>
            </div>
          </mat-drawer>
          <mat-drawer-content>
            <div *ngIf="SKILLS?.length > 0; else noItem">
              <div *ngFor="let skill of SKILLS | filter:'skillGroup':filteredValue">
                <div class="skill">
                  <mat-accordion>
                    <mat-expansion-panel>
                      <mat-expansion-panel-header>
                        <mat-panel-title>{{ skill.skillname }} </mat-panel-title>
                        <mat-progress-bar
                          class="progress-bar"
                          [value]="skill.skillvalue"
                          [color]="'accent'"
                          [mode]="'buffer'"
                        ></mat-progress-bar>
                        <mat-panel-description> </mat-panel-description>
                      </mat-expansion-panel-header>
                      <div>{{ skill.description }}</div>
                    </mat-expansion-panel>
                  </mat-accordion>
                </div>
              </div>
            </div>
            <ng-template #noItem>
              <app-data-loader></app-data-loader>
            </ng-template>
          </mat-drawer-content>
        </mat-drawer-container>
    

When I click on the div element with the id "filter", I update the value of the variable filteredValue. However, the ngFor loop does not display the filtered results as expected. Even though I can see the values returned from the pipe while debugging, they are not being displayed in the ngFor loop. Can you help me identify where I made a mistake?

Answer №1

If you are attempting to perform operations on a collection within a *ngFor directive to filter the collection before looping through it, there is a recommended approach.

According to the Angular documentation section on pipes, it is advised not to use filter or order operations directly within an *ngFor directive using pipes (https://angular.io/guide/pipes#appendix-no-filterpipe-or-orderbypipe)

Instead, you can filter your data before binding it to the *ngFor directive in your component:

component.ts

public ngOnInit(): void {
    requestCollectionFromApi().subscribe(result => {
        skillGruppen = filter(result, 'skillGruppe');
    });
}

private filter(result: Array, unique: string): Array {
    // Implement your filter logic here and return a new array with filtered data.
}

Then, in your HTML, you can remove the pipe usage:

<div *ngFor="let skillGruppe of skillGruppen">
  <button mat-button class="filter">
     <div (click)="filterSkills(filter.textContent)" #filter>
         {{ skillGruppe.skillGruppe }}
      </div>
    </button>
</div>

This approach should help you achieve the desired functionality without violating the recommendations mentioned in the Angular documentation.

Answer №2

Consider converting your key value pair, which are the parameters for filtering, into an object format.

Afterwards, implement a solution similar to the following code snippet:

export class CustomFilterPipe implements PipeTransform {
    transform<T>(elements: T[], filterParams: {key: string, value: any}): T[] {
        if (!elements || !filterParams) {
            return elements;
        }        
        return elements.filter(element => element[filterParams['key']] == filterParams['value']);
    }
}

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

A guide on exporting an Excel file with Spring Boot and Angular 2

To fulfill the requirements of my project, I am tasked with exporting customer data into an Excel file. Utilizing a table structure using Hibernate build. Here is my controller code: @RequestMapping(value="exporttoexcel", method= RequestMethod.GET, prod ...

What is the method for substituting one text with another using two-way data binding?

I implemented two different cases in my Mat-Table. When there is no data, the user will see a message saying "No Data Found". However, if the user enters text in the filter search, the "No Data Found" message should be hidden and replaced with the entered ...

Is it possible to visually distinguish the selected mat-grid-tile? Particularly when they are being created dynamically

On the user interface, I have a dynamic display of mat-grid-tile within a mat-grid-list. These tiles change in number and data based on backend values. When a user clicks on a mat-grid-tile, it triggers a function that receives the tile's data. My goa ...

Show image using Typescript model in Angular application

In my Angular (v8) project, I have a profile page where I typically display the user's photo using the following method: <img class="profile-user-img" src="./DemoController/GetPhoto?Id={{rec.Id}}" /> However, I am considering an alternative ap ...

What is the method for defining functions that accept two different object types in Typescript?

After encountering the same issue multiple times, I've decided it's time to address it: How can functions that accept two different object types be defined in Typescript? I've referred to https://www.typescriptlang.org/docs/handbook/unions ...

I am unable to utilize the outcome of a custom hook within a function or within an effect hook

I've developed a unique custom hook that retrieves a list of individuals File: persons.hooks.ts import {useEffect, useState} from "react"; import Person from "../../models/person/Person"; const usePersons = () => { const ...

Angular 2: Issue with data table not updating after item deletion

I need assistance with updating a data table after deleting an item. The database is updated correctly when I delete an item, but the table does not automatically refresh to reflect the changes. managenews.component.ts import { Component, OnInit } from ...

Accessing instance variables from a chained observable function in Angular 2/Typescript

Currently, I am utilizing Angular2 along with Typescript. Let's assume that there is a dummy login component and an authentication service responsible for token authentication. In one of the map functions, I intend to set the variable authenticated as ...

What is the best way to include documentation for custom components using jsDoc?

Within my Vuejs inline template components, we typically register the component in a javascript file and define its template in html. An example of such a component is shown below: Vue.component('compare-benefits', { data() { // By return ...

Enhancing SQLite syntax in Ionic 2: A fresh approach!

Having trouble with updating my SQLite table using this script, I've edited the query but it still doesn't work. try{ this.sqlite.create({ name: 'data.db', location: 'default' }) .then((db: SQLiteObject) => ...

What is the correct way to utilize refetchOnReconnect for a builder.mutation endpoint in @redux/toolkit/query?

I'm having an issue with the Redux refetchOnReconnect option not working even after I have called the setupListener(store.dispatch) in my redux store.tsx file and set refetchOnReconnect=true to the endpoint hook call. store.tsx file 'use client& ...

The @Input directive is not compatible with the OnPush change detection strategy

page.html <app-parcel-delivery-cost-promo [parcelDeliveryCost]="parcelDeliveryCost"> </app-parcel-delivery-cost-promo> page.ts changeDetection: ChangeDetectionStrategy.OnPush, parcelDeliveryCost: Partial<ParcelDeliveryCostModel>; ...

Steps for Adding a JS file to Ionic 3

I'm trying to figure out how to access a variable from an external JS file that I included in the assets/data folder. Here's what I've attempted: I placed test.js in the assets/data folder. In test.js, I added a variable testvar = "hello ...

How can I enable autofocus on a matInput element when clicking in Angular 6?

Is there a way to set focus on an input element after a click event, similar to how it works on the Google Login page? I've tried using @ViewChild('id') and document.getElementId('id'), but it always returns null or undefined. How ...

Angular 6: Harnessing the Power of RouterLinks

Can you navigate to a different section of another page using the defined ID without having to reload the entire page? ...

Access the Angular directive instance before it is actually rendered

Is it possible to access an Angular directive instance even if it has not been rendered yet? Let's say I have an app-component and a baz-directive. I want to be able to get the directive instance even if it is not currently shown or rendered in the D ...

Upon initial page load, the distinctUntilChanged() function will not be triggered

Upon loading a page, I initiate the following method and utilize the returned list in a dropdown menu. The tap and switchMap functions are run as expected, however, the distinctUntilChanged function does not execute upon page load. Once the page is loade ...

Why won't angular ng update work? Is there a timeout issue with the proxy settings?

I am encountering a problem with my angular project. When I am at work, I use a proxy, but when I am at home, I do not. So I added the following: npm config set https-proxy http://xx.xx.xx.xx:9090 npm config set proxy http://xx.xx.xx.xx:9090 and it works ...

Can an Observable be created that emits an array produced by awaiting asynchronous methods?

I've encountered an issue with the following method: get fileResults$(): Observable<File[]> { return this.ngRedux.select<ICommunicationState>('communication').pipe(map(newState => { const files: File[] = []; ...

Tips for maintaining the original data type while passing arguments to subsequent functions?

Is there a way to preserve generic type information when using typeof with functions or classes? For instance, in the code snippet below, variables exampleNumber and exampleString are of type Example<unknown>. How can I make them have types Example& ...