Tips for resolving an issue with an array and the find method?

Seeking guidance on using the find method. Specifically, I am tasked with searching an array to find a specific string match. The catch is that this string may be nested within one of the objects in its child array. I attempted to create an if statement in my function to handle this scenario while looping through the array, but it did not produce the expected result. Could you please point out where I went wrong?

P.S. To clarify, if the object "newList" contains "items", the comparison should be made within the "items" array under the "role" key. If "items" are not present for the object, then the search should be conducted within the object itself against the "role" key.

const newList = [
    {
        role: "role111",
        title: "title1",
    },
    {
        role: "role222",
        title: "title2",
    },
    {
        role: "role333",
        title: "title3",
    },
    {
        role: "role444",
        title: "title4",
        items: [{
            role: "role555",
            title: "title5",
        }, {
            role: "role666",
            title: "title6",
        }, {
            role: "role777",
            title: "title7",
        },]
    },
    {
        role: "role888",
        title: "title8",
    },
];

const url = "role7";


export const findAfterRefresh = (list, url) =>
    list.find((item) => {
        if (item.items && item.items?.length > 0) {
            return item.items.find((childrenITem) => childrenITem.role.includes(url));
        }
        return item.role.includes(url);
    });
;


findAfterRefresh(newList, url);

Answer №1

Your solution was almost there, but using the find method on newList will only return elements from newList, not from the items array within those elements. Also, since you're looking for the value of role, not the element itself, the find method isn't the best choice for your current data structure. However, if you're determined to use find, there is a workaround.

Instead, a simple loop with recursion can achieve the desired result:

/*export*/ const findAfterRefresh = (list, url) => {
    for (const item of list) {
        if (item.role?.includes(url)) {
            return item.role;
        }
        if (item.items?.length) {
            const childRole = findAfterRefresh(item.items, url);
            if (childRole) {
                return childRole;
            }
        }
    }
};

Here's an annotated version of the code:

/*export*/ const findAfterRefresh = (list, url) => {
    // Loop through the given list...
    for (const item of list) {
        // ...check the role of this item
        // (Remove   v-- this `?` if `role` will always be there)
        if (item.role?.includes(url)) {
            return item.role;
        }
        // If this item has child items, check them recursively
        if (item.items?.length) {
            // Search child items using recursion
            const childRole = findAfterRefresh(item.items, url);
            if (childRole) {
                // Return the found role
                return childRole;
            }
            // Continue looping if role not found
        }
    }
};

Live Example:

... (the rest of the code remains the same as in the original text) ...

Note: I made some modifications to the 'role' containing 'role7' so you can see that the code returns the complete 'role', not just the part matching the 'url'.


If you still want to use the find method, you can first create a flat array of roles:

// Creates a new array of 'role' values including child elements
// (may contain 'undefined' if any 'role' property is missing)
const flattenRoles = (list) =>
  (list ?? []).flatMap((item) => [item.role, ...flattenRoles(item.items)]);

/*export*/ const findAfterRefresh = (list, url) => {
  return flattenRoles(list).find((role) => role?.includes(url));
};

This code is shorter but generates temporary arrays and traverses the full list before searching for roles, unlike the earlier version which stops at the first match. While this may not matter much for a reasonable list size like 'newList', it's something to keep in mind. (Personally, I'd prefer the earlier version over this one.)

See it in action here:

... (the rest of the code remains the same as in the original text) ...


In response to a comment asking about ESLint rules:

...how much do you think eslint is right in this case?

The decision depends on your requirements. For modern environments supporting ES2015+, 'regenerator-runtime' is unnecessary. As major outdated environments like IE11 are no longer relevant, explicit avoidance of 'regenerator-runtime' might not be needed. If compatibility is crucial and avoiding 'regenerator-runtime' is a priority, you can replace the 'for-of' loop with 'some' for iteration:

... (the continued code remains the same as in the original text) ...

...and the error on 'childRole' from TypeScript is TS7022...

The TypeScript warning results from the lack of type annotations in the JavaScript code provided, as the initial question did not center around TypeScript. Adding appropriate type annotations should resolve the issue without trouble.

Answer №2

From my perspective, the task at hand involves filtering the newList to include only objects that have the string role7 in their role property, whether it be in the main object or in child array objects. If this is correct, the recommended approach is to utilize the Array.filter() method instead of Array.find(), as the latter will only return the first element that meets the criteria from the provided array.

See below for a live demonstration:

const newList = [
  {
    role: "role111",
    title: "title1",
  },
  {
    role: "role777",
    title: "title2",
  },
  {
    role: "role333",
    title: "title3",
  },
  {
    role: "role444",
    title: "title4",
    items: [{
      role: "role555",
      title: "title5",
    }, {
      role: "role666",
      title: "title6",
    }, {
      role: "role777",
      title: "title7",
    },]
  },
  {
    role: "role888",
    title: "title8",
  },
];

const url = "role7";

const findAfterRefresh = (list, url) =>
list.filter((item) => {
  return (item.role.includes(url)) ? item :
  item.items = item.items?.filter((childrenITem) => childrenITem.role.includes(url));
});

console.log(findAfterRefresh(newList, url));

Answer №3

After reviewing various solutions, I streamlined my code by converting the raw array value into a 2D array where each nested array holds the role and item values.

This approach allows the function's output to be versatile for tasks related to the roles and titles of these items, while also creating an easily iterable array.

const targetUrl = "role6"; 

const findItemAfterRefresh = (list) =>{
    let foundItems = []
    list.find((item) => {
        foundItems.push([item.role, item.title]);
        if (item.items !== undefined) {
            item.items.find((nestedItem) => {
                foundItems.push([nestedItem.role, nestedItem.title]);
            })
        }
    });
    return foundItems;
}

for(let index in findItemAfterRefresh(newList)){
    if (findItemAfterRefresh(newList)[index].includes(targetUrl)) {
        console.log(findItemAfterRefresh(newList)[index].includes(targetUrl)); break;
    }
}
//output of findItemAfterRefresh: [[role1,title1],[role2,title2][... etc 
//ouput of the for loop at the bottom: true  

Answer №4

Successfully completed the task.

Note: Upon closer inspection, I realized that the code at the end uses "for" instead of "find." Hopefully, this won't cause any issues.

const newList = [
    {
        role: "role1",
        title: "title1",
    },
    {
        role: "role2",
        title: "title2",
    },
    {
        role: "role3",
        title: "title3",
    },
    {
        role: "role4",
        title: "title4",
        items: [{
            role: "role5",
            title: "title5",
        }, {
            role: "role6",
            title: "title6",
        }, {
            role: "role7",
            title: "title7",
        },]
    }
];

const url = "role2";


const findAfterRefresh = (list, url) => {
    for(const singleItem of Object.values(list)) {
        if(singleItem.items && singleItem.items?.length > 0) {
            return singleItem.items.find(child => child.role === url);
        };
        if(!singleItem.role.includes(url)) {
            continue;
        };
        return singleItem;
    }
};


findAfterRefresh(newList, url);

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

Limiting the style of an input element

How can I mask the input field within an <input type="text" /> tag to restrict the user to a specific format of [].[], with any number of characters allowed between the brackets? For example: "[Analysis].[Analysis]" or another instance: "[Analysi ...

Conversation with form component in angular2

I am currently using ng2-bootstrap-modal. For adding a sample form to the example Confirm Dialog, check out ng2-bootstrap-modal. To change the template: <div class="modal-dialog"> <div class="modal-content"> <form [formGroup]="login ...

Transforming an array of strings into an array: a guide

An API call is returning an object with the following structure: data = { ... filter: "[1,2,3]" ... } I need to convert the string of array into an actual array of numbers, like [1,2,3]. Thank you! ...

What is the best way to pause function execution until a user action is completed within a separate Modal?

I'm currently working on a drink tracking application. Users have the ability to add drinks, but there is also a drink limit feature in place to alert them when they reach their set limit. A modal will pop up with options to cancel or continue adding ...

Creating an interface that accurately infers the correct type based on the context

I have an example below of what I aim to achieve. My goal is to start with an empty list of DbTransactInput and then add objects to the array. I experimented with mapped types to ensure that the "Items" in the "Put" property infer the correct data type, w ...

Can anyone figure out why this code is not functioning properly? It seems to be targeting the body element and all of

Currently, I am utilizing jqtouch to create a mobile website. In addition to this, I am incorporating a gallery image slider into the website. However, I have encountered an issue where the images do not display when placed between <div id="project_name ...

Is there a way to invoke a function once grecaptcha.execute() has completed running, but in response to a particular event?

Presently, the JavaScript function grecaptcha.execute is triggered on page load, as shown in the first example below. This means that the reCAPTCHA challenge occurs as soon as the page loads. A more ideal scenario would be to trigger it when the form submi ...

Vue's getComponentName method now properly returns a function instead of returning 'undefined'

After tirelessly working on upgrading my project from Vue 2.6 to 2.7, I've managed to resolve most of the issues. However, there is a persistent problem with certain files that have cased props, triggering Vue to generate an error message known as a & ...

Differentiate the items within a list containing identical divs using JavaScript

Currently, I am expanding my knowledge in HTML, CSS, and JS by incorporating Angular and JQuery. In one of my projects, there is a div labeled "eventBoxes" where multiple divs known as "eventBox" can be added. I have created a template for the eventBox i ...

Choose the tab labeled "2" within a segment of the webpage

index.html#section takes you to a specific section of a webpage. However, I am interested in picking the second tab within a section of the page. I'm uncertain if this can be achieved without relying on JavaScript, but employing the Tab Content Script ...

Utilizing SASS, JavaScript, and HTML for seamless development with Browser Sync for live syncing and

I've been on a quest to find a solution that covers the following requirements: Convert SASS to CSS Post-process CSS Minify CSS Move it to a different location Bundle all Javascript into one file Create compatibility for older browsers Tre ...

SonarQube flagging a suggestion to "eliminate this unnecessary assignment to a local variable"

Why am I encountering an error with SonarQube? How can I resolve it since the rule page does not offer a specific solution? The suggestion is to eliminate the unnecessary assignment to the local variable "validateAddressRequest". validateAddress() { ...

Prevent the onClick function of the outer div from being triggered by clicking on the inner div

Similar Question: Stop parent container click event from firing when hyperlink clicked My issue is <div onClick="someJScode();"> ... <div></div> ... </div> I need to prevent someJScode() from executing when the inner di ...

Update and swap out outdated material

Struggling with replacing old content in a div after using AJAX. The issue is that both the new and old content are appearing inside the div. Here is my current Ajax code: $('#vu').on("click", function(e){ $.ajax({ url: 'url to pag ...

Adding li elements dynamically, how can we now dynamically remove them using hyperlinks?

Please refrain from using jQuery code, as my main focus is on learning javascript. I am currently experimenting with adding li items dynamically to a ul when a button on the HTML page is clicked. Here's a sample implementation: HTML: <ul id="myL ...

Change the anchor text dynamically with JQuery

The page contains href links with incomplete text. For example, the link text displayed on the page is "link1", but it should actually be "link1 - Module33". Both the page text and actual text start with the same initial text ("link1" in this case). I retr ...

Stop allowing the entry of zero after a minus sign

One of the features on our platform allows users to input a number that will be automatically converted to have a negative sign. However, we want to ensure that users are unable to manually add a negative sign themselves. We need to find a solution to pre ...

When a React page is re-rendered using useEffect, it automatically scrolls back to the

Every time I utilize the <Tabs> component, the onChange method triggers the handleTabChange function. This leads to the component being called again and after repainting, the useEffect is triggered causing the page to scroll back to the top. How can ...

web browser editing tool

Do you know which library was utilized to create this JSON editor? You can find it at . The editor efficiently checks the syntax and shows errors when necessary. ...

Updating a string in JavaScript by dynamically adding values from a JSON object

In my current function, I am making a request to fetch data and storing it as an object (OBJ). Afterwards, I make another request to get a new URL that requires me to update the URL with values from the stored data. The information saved in the object is ...