How to Hide Parent Items in Angular 2 Using *ngFor

I am dealing with a data structure where each parent has multiple child items. I am trying to hide duplicate parent items, but accidentally ended up hiding all duplicated records instead. I followed a tutorial, but now I need help fixing this issue. I only want to hide the parent items, not remove the entire record.

My datatable:        Failed Results:            Expected Results:

Parent Child         Parent Child                  Parent Child 
Lee    123           Lee    123                     Lee    123
Lee    124           Rose   111                            124
Lee    125                                                 125
Rose   111                                          Rose   111

code:

 //our root app component
    import { Component, NgModule, VERSION } from '@angular/core'
    import { BrowserModule } from '@angular/platform-browser'
    import { Pipe, PipeTransform, Injectable } from '@angular/core'


    @Pipe({
        name: 'uniqFilter',
        pure: false
    })
    @Injectable()
    export class UniquePipe implements PipeTransform {
        transform(items: any[], args: any[]): any {
            // filter items array, items which match and return true will be kept, false will be filtered out

            return _.uniqBy(items, args);
        }
    }

    @Component({
      selector: 'my-app',
      providers: [],
      template: `
        <div>
                    <ul>
                        <li *ngFor="let account of accounts | uniqFilter:'Parent'">{{ account.Parent }} and {{ account.Child }}</li>
                    </ul>
        </div>
      `,
      directives: [],
      pipes: [UniquePipe]
    })
    export class App {
      constructor() {
          this.accounts = [{
              "Parent": 'Lee',
              "Child": "4/6/2016"
          },
          {
              "Parent": 'Lee',
              "Child": "4/7/2016"
          },

          {
              "Parent": 'Rose',
              "Child": "4/9/2016"
          },
          {
              "Parent": 'Rose',
              "Child": "4/10/2016"
          },

          {
              "Parent": 'Lee',
              "Child": "4/12/2016"
          }];
      }
    }

    @NgModule({
      imports: [ BrowserModule ],
      declarations: [ App, UniquePipe ],
      bootstrap: [ App ],
      providers: [ UniquePipe ]
    })
    export class AppModule {}

Answer №1

I wouldn't opt for using a pipe in this scenario, and I haven't yet incorporated the separation of concerns.

Take a look at the demo here along with the explanation below

To begin with, update your app component by adding two methods to it:

First method sorts your data based on the key (credit goes to this answer here). This helps in easily determining if a parent has been listed already

// sort on key values
 keysrt(key,desc) {
   return function(a,b){
   return desc ? ~~(a[key] < b[key]) : ~~(a[key] > b[key]);
   }
}

And another method that checks if the last item in the list had the same parent as the current item

lastParent(i){
    if(i>0){
      if (this.accounts[i].Parent === this.accounts[i-1].Parent)
        return false;
      else
        return true;
    }
    else
      return true;
}

Next, ensure to initialize your account array in the app component. It's recommended to do this before constructor

account: any[];

Then, modify your constructor accordingly. Remember to sort after filling the array.

constructor() {
      this.accounts = [{
          "Parent": 'Lee',
          "Child": "4/6/2016"
      },
      {
          "Parent": 'Lee',
          "Child": "4/7/2016"
      },

      {
          "Parent": 'Rose',
          "Child": "4/9/2016"
      },
      {
          "Parent": 'Rose',
          "Child": "4/10/2016"
      },

      {
          "Parent": 'Lee',
          "Child": "4/12/2016"
      }];

      this.accounts.sort(this.keysrt('Parent', true)); 
}

Lastly, adjust your HTML template like this. You can change the tags for better appearance, but this structure should give you desired output. Use index to track loop progress and ngIf directive to decide whether to display the parent based on lastParent function

<div>
     <ul>
         <li *ngFor="let account of accounts; let i = index">  
             <div *ngIf = "lastParent(i)">{{ account.Parent}}</div>
              and {{ account.Child }}
         </li>
     </ul>
</div>

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

I am experiencing an issue with the PUT method on my API as it is not correctly setting the req.body data

Below is the code snippet for implementing the PUT method: [/api/[id].ts] case "PUT": try { const user = await UserModel.findOneAndUpdate( { _id: id, }, { $set: req.body, ...

IE11 displaying empty placeholders instead of PrimeNG icons after deployment on server

Currently, I am in the midst of an Angular project that heavily relies on PrimeNg for various components. While everything runs smoothly when testing the project locally across all browsers (including IE11 and Chrome), a hiccup arises once the project is ...

Angular Universal SSR - prerendering static content

After updating to the latest Angular version 10, I encountered an issue when trying to run a static prerender. The error message displayed is: Unhandled Promise rejection: Cannot read property 'moduleType' of undefined. Despite trying various con ...

I can't seem to understand why I am receiving an undefined property when trying to access an

While working with typescript and react within a project created using create-react-app, I encountered an issue during runtime: Cannot read property 'Customer' of undefined. This error occurred while utilizing the following module imports: impor ...

There was an error in reading the 'nativeElement' property in Angular's waveform library, resulting in a TypeError

This is the code I wrote, but it is showing an error: The waveform should be created, but the function to create the waveform is not working. startRecording() { this.mediaSectionVisible = false; if (!this.isRecording) { this.isRecording = t ...

issue with global variable not functioning properly within a sub-function in Angular 7

I have a question that needs clarification import { Component, OnInit,ViewChild,ElementRef } from '@angular/core'; import {Http,Headers} from "@angular/http"; import { Observable, Subject, asapScheduler, pipe, of, from, interval, merge, ...

What could be the reason for the defaultCommandTimeout not functioning as expected in my script

Is there a way to wait for only one particular element in Cypress without having to add wait commands everywhere in the test framework? I've come across the solution of adding defaultCommandTimeout in the cypress.json file, but I don't want it t ...

The Angular4 service being utilized is not defined within the public function

Currently, I am facing an issue with my services setup. I have two services in place - the first service is responsible for the map function within the http CRUD Function, while the second service is supposed to perform a task that is provided by the first ...

Angular 7 error: Form control with name property does not have a valid value accessor

Currently, I am utilizing angular 7 and have a parent and child component set up as demonstrated in the Stackblitz link provided below. Strangely enough, when I assign the formControlName from the child component using "id", everything functions flawlessly ...

Broaden the scope of the generic interface utilized within the package

Wanting to incorporate automatic behaviors in RTK Query, I decided to implement debounced mutations and handle optimistic updates before the actual mutation request is made. The implementation has been successful so far. However, I am now focusing on gett ...

Having trouble processing images in multi-file components with Vue and TypeScript

Recently, I reorganized my component setup by implementing a multi-file structure: src/components/ui/navbar/ Navbar.component.ts navbar.html navbar.scss Within the navbar.html file, there was an issue with a base64-encoded image <img /> ...

Using a static value in the comparator is necessary for Array.find to function properly in Typescript

Looking to retrieve an item from an array: const device = this.selectedDevtype.devices.find(item => console.log(this.deviceID); return item.device_id === this.deviceID; }); console.log(device); When this.deviceID is logged, it shows "4", but t ...

How can we limit the CSS properties that can be used in an interpolated manner by defining a restricted TS type for CSS props based on emotions?

When dealing with emotions, how can we specify a restricted TS type for the css prop to only allow certain css properties to be interpolated? For instance, consider the following scenario: // This is considered valid css = {{ color: 'white', ...

Using an array to enforce form validation rules in Angular, including prohibited form values

I am currently developing a basic Angular form with specific validation requirements: The input must not be left empty The input cannot match any of the values stored in the array forbiddenValues. While I understand how to implement the required validat ...

Should I return X in async functions, or should I return "Promise.Resolve(X)"?

I've always found this to be a tricky concept to fully grasp. Let's delve into async functions in Typescript. Which implementation is accurate? async function asyncFunctionOne(string1: string, string2: string, string3: string) { var returnOb ...

using angular and firestore to grant public reading permission for a document

As a student developer, I recently integrated Firestore into my Angular app and encountered some challenges with the security rules. My goal: I want to display a Firestore document in an Angular view using template binding. The document should be visible ...

Implement an interface with a specific number of properties in TypeScript

I am attempting to create a custom type that defines an object with a specific number of key-value pairs, where both the key and value are required to be numbers. Here is what I envision: type MatchResult = { [key: number]: number; [key: number]: numbe ...

Exploring Angular's filtering capabilities and the ngModelChange binding

Currently, I am in the process of working on a project for a hotel. Specifically, I have been focusing on developing a reservation screen where users can input information such as the hotel name, region name, check-in and check-out dates, along with the nu ...

Step-by-step guide on building a wrapper child component for a React navigator

When using the Tab.Navigator component, it is important to note that only the Tab.Screen component can be a direct child component. Is there a way in Typescript to convert or cast the Tab.Screen Type to the TabButton function? const App = () => { retur ...

Class for Angular input validation when user doesn't enter text

When it comes to Angular forms, there are certain CSS input validation classes such as pristine, dirty, and invalid. One common issue arises when dealing with an input that has a minimum length requirement - we want to avoid displaying an error message in ...