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

Do developers usually commit or ignore the environment.ts file in their projects?

Should the file src\environments\environment.ts be committed or added to the .gitignore file? In a fresh Angular project (8.x), I have noticed that this file is not included in the .gitignore file. My assumption is that it's like this becau ...

Function in Typescript that can return multiple data types

I recently started learning about TypeScript and its concepts. During my practice sessions, I encountered a problem that left me puzzled. There is a function named `functionA` which returns an object based on the response received from an API. type Combina ...

Setting up popover functionality in TypeScript with Bootstrap 4

Seeking assistance with initializing popovers using TypeScript. I am attempting to initialize each element with the data-toggle="popover" attribute found on the page using querySelectorAll(). Here is an example of what I have tried so far: export class P ...

Get the socket identification from ngx-socket-io

After incorporating ngx-socket-io into my project, I encountered a hurdle while attempting to obtain the socket id. Is there anyone who has knowledge on how this can be accomplished? (I am utilizing service initialization instead of the one in the app Mo ...

Generating a new object using an existing one in Typescript

I received a service response containing the following object: let contentArray = { "errorMessages":[ ], "output":[ { "id":1, "excecuteDate":"2022-02-04T13:34:20" ...

Error in Angular not providing code line numbers for debugging

There seems to be an error shown in the image below, with no line number displayed in the code and no errors appearing in the terminal. The codebase is large, and this error is occurring in the Chrome console. Clicking on the line numbers of the bundles do ...

Encountering TypeScript errors while trying to implement Headless UI documentation

import { forwardRef } from 'react' import Link from 'next/link' import { Menu } from '@headlessui/react' const MyLink = forwardRef((props, ref) => { let { href, children, ...rest } = props return ( <Link href={href}&g ...

Encountering an error when performing unit tests in Angular where the property 'navigate' is undefined

Why am I encountering this error while attempting to run a unit test on a function that needs to be invoked? Here is the code snippet from the .spec.ts file: it(' should call the server when the ok button is clicked, to send the selected code option& ...

Utilizing a Link element in conjunction with ListItem and Typescript for enhanced functionality

I am currently using material-ui version 3.5.1 My goal is to have ListItem utilize the Link component in the following manner: <ListItem component={Link} to="/some/path"> <ListItemText primary="Text" /> </ListItem> However, when I tr ...

Using Ionic 3 to create a list view that includes buttons linked to the items clicked

I need assistance with modifying the button icon in a list layout: <ion-list inset *ngFor="let audio of event.audios; let i = index"> <ion-item> <div class="item-text-center item-text-wrap"> {{audio.fileName}} </div& ...

How can I accurately determine the true dimensions of an image in Angular, including any resizing that may

Here is an image: @ViewChild('image') readonly photo: ElementRef; The HTML code for the image is: <img #photo class="pic" /> How can I find the original size (width, height) as well as the resized dimensions after applying CSS a ...

Enhance Leaflet Marker functionality using Typescript

I am currently tackling a project that involves using Typescript and Leaflet. Traditionally, to extend the leaflet marker in JavaScript, it is done like this: L.Marker.Foo = L.Marker.extend({...}); But when I attempt to do this in Typescript, I encounter ...

Having trouble with sending values to Angular 7 components' HTML pages

Struggling with a simple task and encountering an error: Code snippet below: app.component.html <div class="col-md-{{myvalue}}">stuff here</div> app.component.ts myvalue: string; ngOnInit() { this.myvalue('6'); } Seeing th ...

What are the steps for integrating Angularfire2 into an Angular application?

Trying to integrate Angularfire2 into a fresh Angular project, but encountered an issue while following the official documentation. This is the guide I followed Upon reaching step 7 - Inject AngularFirestore, console errors were displayed: If anyone has ...

Angular OAuth2 OIDC password reset process

Currently, I am integrating B2C into my Angular (8) application using angular-oauth2-oidc. I have successfully implemented sign-in and sign-out policies, as well as configuring the angular-oauth2-oidc service. However, when utilizing the standard Microsoft ...

I am having trouble initializing npm due to an error

I am currently working on a Node.js project but I am having trouble starting Node.js. In my existing Angular project, and after creating a new project with the following commands: sudo npm install -g @angular/cli After that, run: ng new mean-angular5 ...

When setting up Angular material, be prepared for a thorough audit uncovering nearly 600 vulnerabilities

I want to utilize the drag and drop features provided by the @angular/material module, however, when I install it using angular cli, multiple vulnerabilities are flagged during the audit process. While the program functions as expected, attempting to run n ...

Experience the magic of Angular combined with the versatile ng-image-slider; displaying a single image at a

I want to customize my ng-image-slider in my app so that only one image is displayed at a time, while also ensuring that it remains responsive. Besides adjusting the "imageSize" input and manipulating the width/height of the images, what other options do I ...

What is the reason that TypeScript cannot replace a method of the base class with a subtype?

Here's a straightforward example. type Callback<T> = (sender: T) => void; class Warehouse<T> { private callbacks: Callback<T>[]; public constructor(callbacks: Callback<T>[]) { this.callbacks = callbacks; ...

You appear to be missing a dependency on either "@angular/core" or "rxjs" when attempting to deploy your MEAN app on Heroku. This issue must be resolved

I encountered an issue while trying to deploy my MEAN-stack application on Heroku. My app was built mainly following this tutorial series. However, during the deployment process by pushing to GIT, I received the following error: <a href="/cdn-cgi/l/emai ...