Angular Custom Pipe - Grouping by Substrings of Strings

In my Angular project, I developed a custom pipe that allows for grouping an array of objects based on a specific property:

import { Pipe, PipeTransform } from '@angular/core';

@Pipe({name: 'groupBy'})
export class GroupByPipe implements PipeTransform {
  transform(value: Array<any>, field: string): Array<any> {
  const groupedObj = value.reduce((prev, cur)=> {
      if(!prev[cur[field]]) {
        prev[cur[field]] = [cur];
      } else {
        prev[cur[field]].push(cur);
      }
      return prev;
    }, {});

    return Object.keys(groupedObj).map(key => ({ key:key, value: groupedObj[key] }));
  }
}

    <div>
      <h2>Group by department</h2>
<ul>
    <li *ngFor="let group of employees | groupBy:'department'">Department{{group.key}}
        <ul>
            <li *ngFor="let event of group.value">
            {{event.firstName}} {{event.lastName}}
            </li>
        </ul>
    </li>
</ul>

The implementation above works flawlessly!

However, now I am looking to tackle a different challenge.

In the example within the app.component: https://stackblitz.com/edit/angular-rc3njv

I have an array of strings:

 email = ["<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="60020c0120070d01090c4e030f0d">[email protected]</a>", "<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="cbacacac8baca6aaa2a7e5a8a4a6">[email protected]</a>", "<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="c1bbbbbb81a6aca0a8adefa2aeac">[email protected]</a>","<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="ef828282af87809b828e8683c18c8082">[email protected]</a>"]

and I aim to group this array based on substring. For instance: @gmail.com forms one group with emails like "[email protected]", "[email protected]", "[email protected]"; @hotmail is another group containing "[email protected]"

Does anyone have insights on how to customize the existing pipe in the provided example so it can effectively group an array of strings based on substrings?

Appreciate any help!

Answer №1

If you want to group items based on their extensions, here is a method you can use.

A Stackblitz Demo has been created for reference.

Your Sample Data:

const emails = ["<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="5b39373a1b3c363a323775383436">[email protected]</a>", "<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="92f5f5f5d2f5fff3fbfebcf1fdff">[email protected]</a>", "<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="5a2020201a3d373b333674393537">[email protected]</a>","<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="3d5050507d555249505c5451135e5250">[email protected]</a>"];


Grouping Method 1: { '@gmail.com': ['...', '...'] }

// Get the unique list of extensions from the emails
// Result: [ '@gmail.com', '@hotmail.com' ]
const extensions = Array.from(new Set(emails.map(email => email.match(/@.*/ig)[0])));    


// Find the index of extension from the extensions list
// Result: e.g <a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="a2c0cec3e2c5cfc3cbce8cc1cdcf">[email protected]</a> -> 0 as '@gmail.com' is found at index 0 in extensions [ '@gmail.com', '@hotmail.com' ]
const getEmailExtensionIndex = email => extensions.findIndex(extension => email.includes(extension));


// Group the emails based on their extensions
const result = emails.reduce((acc, email) => {
  // Get the extension from the email e.g <a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="a7c5cbc6e7c0cac6cecb89c4c8ca">[email protected]</a> -> @gmail.com
  const extension = extensions[getEmailExtensionIndex(email)];     

  // If the key doesn't exist, set an initial value
  if (!acc[extension]) acc[extension] = [];    

  // Add the email to its corresponding key inside the object
  acc[extension].push(email);

  return acc;
}, {});

Result:

{
  '@gmail.com': [ '<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="44262825042329252d286a272b29">[email protected]</a>', '<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="caadadad8aada7aba3a6e4a9a5a7">[email protected]</a>', '<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="d4aeaeae94b3b9b5bdb8fab7bbb9">[email protected]</a>' ],
  '@hotmail.com': [ '<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="ea878787aa82859e878b8386c4898587">[email protected]</a>' ]
}

Grouping Method 2: [ { key: '' , values: [] } ]

// Use the result from Method #1 defined above const result = emails.reduce(...)
const result2 =  Object.keys(result).map(key => ({ key, values: result[key] }));

Result:

[ 
   { key: '@gmail.com', values: [ '<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="e88a8489a88f85898184c68b8785">[email protected]</a>', '<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="4d2a2a2a0d2a202c2421632e2220">[email protected]</a>', '<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="f8828282b89f95999194d69b9795">[email protected]</a>' ] },
   { key: '@hotmail.com', values: [ '<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="4e2323230e26213a232f2722602d2123">[email protected]</a>' ] } 
]

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

What specific event do I require for the onChange event in React using TypeScript?

I'm facing a problem while working with React TypeScript. I need to type the onChange event for a select element, but the data is coming from event.value instead of event.target.value. What should be the appropriate event to use in this case? Below i ...

Encountering difficulties with showing contact images in phonegap using angularjs

In my project, I encountered an issue where I can fetch and display the contact photo using simple HTML and JavaScript. However, when I attempt to do the same using AngularJS model, I encounter an error. Below is the code snippet that I am struggling with: ...

The error message "Angular 14 + Jest - typescript_1.default.canHaveDecorators is not a function" indicates that

Upon setting up Jest with Angular 14, I encountered the following error message: Test suite failed to run TypeError: typescript_1.default.canHaveDecorators is not a function at TypeScriptReflectionHost.getDecoratorsOfDeclaration (node_modules/jest-prese ...

Ways to halt a script entirely once its tag has been eliminated

I have a script from a page tracker website that runs periodically. Occasionally I need to restart the script from the beginning. To do this, I typically remove the script tag from the DOM and then re-append it. However, because the script utilizes setInt ...

Managing the resizing event of a structural directive while maintaining the original context

I am in the process of creating a custom ngIf directive to handle different platforms. *ifPl="'android' Currently, it is functioning well. When I am on an ios platform, the element is not present in the DOM, and vice versa. However, I would lik ...

Is it necessary for me to cancel subscriptions in my unit tests?

In the scenario where I have a test like the one provided below: it('should return some observable', async(() => { mockBackend.connections.subscribe((mockConnection: MockConnection) => { const responseOptions = new ResponseOptions({ ...

Angular2 API call error: The function .map defaultOptions.merge is not recognized

When attempting to call the API using the post method, I encountered the following error message: this._defaultOptions.merge is not a function ... I looked into some solutions and tried importing the following without success: import 'rxjs/add/ope ...

"Stay entertained with a captivating animated gif that appears when you refresh the

I just implemented this code snippet to enable animated gifs to work after refreshing a webpage. It's functioning properly in Chrome, Safari, and Internet Explorer except for Firefox. Can someone please offer assistance? jQuery: $(img).css("backgrou ...

efficiency of this algorithm

function checkSubset(array1, array2) { const set1 = new Set(array1); const set2 = new Set(array2); for (const element of set2) { if (!set1.has(element)) { return false; } } return true; } Can we consid ...

Steps for adding a delete icon to a text input field and enabling the functionality to delete text

In the code snippet below, I am creating a text input field: <input type="text" class="signup-input text-value" name="" placeholder="e.g. <a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="2d48554c405d41486d">[email pro ...

Tips for avoiding Client DOM XSS vulnerability in JavaScript

Upon completing a checkmarx scan on my code, I received the following message: The method executed at line 23 of ...\action\searchFun.js collects user input for a form element. This input then passes through the code without proper sanitization ...

Checking the interceptor response in NestJs testing

I created a basic interceptor that removes a specific field from a response: import { CallHandler, ExecutionContext, Injectable, NestInterceptor, } from '@nestjs/common'; import { Observable } from 'rxjs'; import { map } ...

JavaScript's replace() method and the $1 issue

My goal is to develop a script that can identify specific patterns within text and then enclose them in particular tags upon identification. $(".shop_attributes td").each(function () { $(this).html(function(i, html) { return html.replace(/E[0- ...

Struggling with implementing a personalized zoom feature in React-Leaflet?

Looking to create a custom Zoom button using react-leaflet Below is the code I have been working on: import React from 'react'; import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider'; import { Map, TileLayer } from 're ...

Create an animation effect where a div increases in height, causing the divs beneath it to shift downward in a

My aim is to create columns of divs where the user can click on a div to see more content as the height expands. I've managed to set this up, but it seems there's an issue with the document flow. When I click on a div in the first column, the div ...

JavaScript form validation: returning focus to textfields

I am currently working on a project where I am using JQuery and JavaScript to create an input form for time values. However, I am facing challenges in getting the JavaScript code to react correctly when incorrect input formats are detected. I have a group ...

Struggling with transferring data rows between tables in Angular with Angular Material

I have implemented a data table using angular material with initial data rows. Additionally, I have included an empty data table where rows can be transferred from the first table. Transferring rows from the first table to the second table is functioning ...

Establish a connection between a variable and the selected value of Mat-select using a form

Within my TypeScript code, there exists a variable named type whose value is provided by its parent component. This type value is essentially a string that has the possibility of being empty upon being received from the parent component. Additionally, in t ...

Specialized Character Formats in TypeScript

In my quest to enhance the clarity in distinguishing different types of strings within my program - such as absolute paths and relative paths, I am seeking a solution that ensures functions can only take or return specific types without errors. Consider t ...

Is it possible to extract content from a remote website by utilizing javascript and iframe?

Are there any resources available for working with iframes in Ruby on Rails? **UPDATE:** I have a link that directs to an external website. I am looking to extract the content from that site and save it within my application. Is this achievable without re ...