0

Let say i have a object response like this

const response = [
    {
        "title": "Menu 1",
        "subMenu": [
            {
                "title": "Menu 1.2"
            }
        ]
    },
    {
        "title": "Menu 2",
    },
    {
        "title": "Menu 3",
        "subMenu": [
            {
                "title": "Menu 3.1",
                "subMenu": [
                    {
                        "title": "Menu 3.2"
                    }
                ]
            }
        ]
    },
    
]

I want to get the object have title "Menu 3.1" using recursion so i wrote this function

const findElement = (arr, title) => {
  for (let index = 0; index < arr.length; index++) {
    const menu = arr[index];
    if (menu.title === title) {
      return menu;
    } else if (menu.subMenu) {
      return findElement(menu.subMenu, title);
    }
  }
};

and call it like this

console.log(findElement(response, "Menu 3.1" ))

but it log 'undefined'? What did i do wrong?

1
  • 1
    trace what is happening, and you'll see that when checking response[0], it goes into menu 1 submenu, and that's it - doesn't even check response[1] Commented Oct 7, 2022 at 8:08

2 Answers 2

3

The issue is, that the code checks response[0], it isn't a match, so checks responsep[0].submenu, but it returns the result of checking that, therefore, the for loop is short-circuited because the target isn't found

What you want to do, when checking sub-menu is check if the there is a result and only return it if there is

A little like this

const response = [{
        "title": "Menu 1",
        "subMenu": [{
                "title": "Menu 1.2"
            }
        ]
    }, {
        "title": "Menu 2",
    }, {
        "title": "Menu 3",
        "subMenu": [{
                "title": "Menu 3.1",
                "subMenu": [{
                        "title": "Menu 3.2"
                    }
                ]
            }
        ]
    },
]

const findElement = (arr, title) => {
    for (let index = 0; index < arr.length; index++) {
        const menu = arr[index];
        if (menu.title === title) {
            return menu;
        } // no need for else since we return above
        if (menu.subMenu) {
            const sub = findElement(menu.subMenu, title);
            if (sub) return sub;
        }
    }
};

console.log(findElement(response, "Menu 3.1"))

Sign up to request clarification or add additional context in comments.

2 Comments

@RoryMcCrossan, that was my testing :p had some console.logs in there so I could describe exactly what the code was doing wrong :p
thanks a lot, the code is working now!
1

I'd definitely use a reducer here:

const reducer = (result, item) =>
  result ||
  (item.title === "Menu 3.1"
    ? item
    : item.subMenu?.reduce(reducer, null) || null)

console.log(response.reduce(reducer, null))

const response = [
  {
    title: "Menu 1",
    subMenu: [
      {
        title: "Menu 1.2"
      }
    ]
  },
  {
    title: "Menu 2"
  },
  {
    title: "Menu 3",
    subMenu: [
      {
        title: "Menu 3.1",
        subMenu: [
          {
            title: "Menu 3.2"
          }
        ]
      }
    ]
  }
]

const findItemByTitle = (items, title) => {
  const reducer = (result, item) =>
    result ||
    (item.title === title
      ? item
      : item.subMenu?.reduce(reducer, null) || null)

  return items.reduce(reducer, null)
}

console.log(findItemByTitle(response, "Menu 3.1"))

  • return result if it's already found
  • else return current item if title matches
  • else return the search for item on current item's submenu if item has submenu (recursion)
  • else return null (=> goes to next item without a result)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.