Filtering an array of objects in Angular5

Attempting to refine the display of products, I noticed a problem where the original array is unintentionally altered, leading to incorrect filtering...

categories consists of an array containing objects with categories {title, products[]}

I aim for categoriesView to serve as a filtered array

filterByKeyword(keyword: string) {
    let k = keyword.toLowerCase();

    this.categoriesView = this.categories.filter((c) => {
      for(let q = 0; q < c.products.length; q++) {
        return c.products[q].title.toLowerCase().indexOf(k) >= 0;
      }
    });

    // Filter products within each category:
    for(let q = 0; q < this.categoriesView.length; q++) {
      for(let z = 0; z < this.categories.length; z++) {
        if(this.categoriesView[q].title == this.categories[z].title){
          this.categoriesView[q].products = this.categories[z].products.filter((p) => {
              return p.title.toLowerCase().indexOf(k) >= 0;
          });
        }
      }
    }

    console.log("Categories View: ", this.categoriesView);
    console.log("Categories: ", this.categories);
}

The initial filter operation on categories functions correctly. However, when delving into products, issues arise and changes are made to the original array.

Answer №1

Apologies for intervening, but I needed to address your filtering process and code implementation.

Your current approach seems inefficient and messy.

I have taken the liberty to rewrite the code for better clarity, simplicity, and functionality:

filterByKeyword(keyword: string) {

    const searchKeyword = keyword.toLowerCase();

    this.categoriesView = this.categories.filter(category => {
      let isMatched = false;
      for(let product of category.products) {
        if(product.title.toLowerCase().includes(searchKeyword)) { 
          isMatched = true; 
        }
      }
      return isMatched;
    });

    // Alternatively, a more concise version
    // this.categoriesView = this.categories.filter(category => category.products.find(product => product.title.toLowerCase().includes(searchKeyword)));

    for (const viewCategory of this.categoriesView) {
      for (const originalCategory of this.categories) {
        if (viewCategory.title === originalCategory.title) {
          viewCategory.products = originalCategory.products.filter(prdct => prdct.title.toLowerCase().includes(searchKeyword));
        }
      }
    }

    console.log("Categories View: ", this.categoriesView);
    console.log("Categories: ", this.categories);
}

Answer №2

Here's a way to make it function properly:

filterByKeyword(keyword: string) {
    const k = keyword.toLowerCase();
    this.categoriesView = this.categories.map(x => Object.assign({}, x));
    this.categoriesView = this.categoriesView.filter((category) => {
        category.products = category.products.filter(
          (product)=> product.title.toLowerCase().includes(k));

        return category.products.length>0 }
      );
    if(this.categoriesView.length===0){
      this.categoriesView = this.categories.map(x => Object.assign({}, x));
    }
  }

Answer №3

When working with javascript, it's important to understand that objects are passed by reference. This means that if you have a variable like categoriesView, it is actually a reference to the original categories array. Any changes made to one will affect the other as well.

If you need to create a separate object without affecting the original, you can use the angular.copy() method. This function allows you to make a copy of an object or array so that any modifications made to the copy won't impact the original data.

this.categoriesView = angular.copy(this.categories.filter((c) => {
  for(let q = 0; q < c.products.length; q++) {
    return c.products[q].title.toLowerCase().indexOf(k) >= 0;
  }
});

For more detailed information on how to use angular.copy(), you can visit the official AngularJS documentation here.

Answer №4

Encountered a problem with:

this.categories.filter( (c) => {...} )

Your array is not being properly iterated as it terminates in the first round. Consider incorporating a temporary boolean as a buffer within your loop, then return it.

Furthermore, contemplate refactoring your code using Array.prototype.map and Array.prototype.reduce, as it will greatly enhance readability.

this.categoriesView = this.categories.filter(c => {
    return c.products.reduce( (acc, product) => {
        return acc || product.title.toLowerCase().includes(k);
    }, false);
});

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 integrating Contact List information into PhoneGap ListView

I'm currently working on a javascript function that reads the device's ContactList and adds them into a javascript array. On my HTML page, I have implemented a listview. However, I am struggling to dynamically add the data from the array into the ...

How can AngularJS load service data following the addition of a new record?

I have been working on adding user records and I want to display the new record instantly. The JavaScript code below is used for inserting records. User creation and displaying the users list are functioning correctly, but the newly inserted records only s ...

Using the import keyword is not allowed when Typescript has been incorporated

Recently, I've been working on integrating TypeScript into an existing project However, I encountered a roadblock with the following error message: SyntaxError: Cannot use import statement outside a module In my helper class (which is not included h ...

having difficulties sorting a react table

This is the complete component code snippet: import { ColumnDef, flexRender, SortingState, useReactTable, getCoreRowModel, } from "@tanstack/react-table"; import { useIntersectionObserver } from "@/hooks"; import { Box, Fl ...

What is the proper way to implement v-model with Vuex in <select> elements?

I included a <select> element in my design: <select v-model="amount" required> <option value="10">10</option> <option value="20">20</option> <option value="25">25</o ...

Typedoc encountering an issue due to the require syntax

I am currently attempting to create documentation using typedoc. The lines in my typescript file are as follows: var validator: any = require('validator'); import * as _ from 'lodash'; var mqtt: any = require('mqtt'); var fs ...

"Creating a dynamic Vue array using computed property from the provided dataset

Let's consider a scenario where data is retrieved from a store: let itemsData=[ {id:1,data:[...]}, {id:2,data:[...]}, {id:3,data:[...]} ] The goal here is to create another array, itemsSelected, that looks like this: let itemsSelected=[ {id:1 ...

Attempting to navigate through nested data within existing mapped data

The data set 1 consists of an array that contains another array called data set 2. Currently, data set 1 is being mapped to display a single-column table with data1.name inside it. The data1.name serves as a clickable button that reveals the related data i ...

"Seeking guidance on getting my carousel functionality up and running in Angular 8 - any

I tried implementing a carousel from the Bootstrap 4 documentation, but it is only displaying one image. How can I modify the carousel to show all images? I am new to using Angular. Below is the code I have: <div class=" bg-success text-white py-5 tex ...

Issues with dynamically loading content into a drop-down menu using AngularJS

Hey there, I need some assistance. I have two select fields, one for states and the other for cities. My goal is to dynamically load cities from a JSON generated on the server when the user changes the selected state. Any help would be greatly appreciated. ...

Using an iframe containing a link to trigger the opening of a colorbox in the

Recently, I encountered a challenge regarding an iframe containing a bar graph. I wanted to achieve that when the graph is clicked, it would open a colorbox with a more detailed graph from the "PARENT" of that iframe. Initially, I managed to get the ifram ...

Identify when a browser tab is closed and determine which specific tab out of all the open tabs was closed

Is there a way to identify when a browser or tab is closed in Angular/JavaScript? I would like to know if there are specific events that can be used for detecting these actions. Any advice, information, or code examples on this topic would be greatly app ...

One simple click to auto-fill the form

I have encountered a problem that has been discussed before, but my lack of coding knowledge is making it difficult for me to find a suitable solution that matches the code on my website. The issue at hand is as follows: I need my form to populate car mak ...

Utilizing Axios for sending post requests to Pinterest API

I am currently facing an issue with making post requests to the Pinterest API. Despite my code appearing to be correct, I consistently receive an error message stating "Invalid Request Body" from the Pinterest API. According to the official documentation ...

What is the best way to arrange the information in JSON in ascending order and display it in a table format?

I am working with a mat-table and have used GET to display my data. I now want to sort the data in ascending order based on the db-nr from my JSON. Here is an excerpt from my JSON: { "period": 12.0, " ...

Adjustable dimensions and the AngularJS framework

Upon page load, a directive is triggered to resize the content to fit within the correct dimensions. However, there seems to be an issue when a service call populates the model of a specific section of content after the resizing has taken place. The elemen ...

Typescript question: What is the specific error type associated with the 'throw' function in express-validator?

I am trying to identify the type of error thrown by this function: validationResult(req).throw() This is how the throw function is defined: throw() { if (!this.isEmpty()) { throw Object.assign(new Error(), utils_1.bindAll(this)); } } Here ...

Adding data to a pre-made JavaScript file template to create a fresh document

In my web application, I have a form with multiple inputs: <form action=""> Title1:<br> <input type="text" name="title1"> <input type="text" name="title1Description"> <br> Title2:<br> <input t ...

Updating a Rails partial using JSON response from an AJAX post request

I recently implemented an AJAX post request in my backend Rails application to upload a file. Upon successful posting, the response contains a JSON list of files. Now, I face the challenge of reloading the file list on my 'detalhes.html.erb' vie ...

Creating a website that adapts based on the subdomain used

Allow me to clarify my issue as best I can. If you need more details, please don't hesitate to ask, and forgive any errors in English as it is not my native language. Main Objective I am managing a website, www.mywebsite.com, that I intend to use fo ...