Creating a Navbar Menu from JSON data with Lodash

I am trying to create a navbar menu from JSON data. Actually I have achieved it but I am looking for feedback not to call getItems twice? How can I improve my code?

Thank you

var _ = require('lodash');

let menuConfig = [
    {
        ID: 1,
        TAG: "M:A",
        PARENT_TAG: "MAIN",
        TITLE: "A Title"
    },
    {
        ID: 2,
        TAG: "AS1",
        PARENT_TAG: "M:A",
        TITLE: "A Subtitle 1"
    },
    {
        ID: 3,
        TAG: "AS2",
        PARENT_TAG: "M:A",
        TITLE: "A Subtitle 2"
    },
    {
        ID: 4,
        TAG: "AS3",
        PARENT_TAG: "M:A",
        TITLE: "A Subtitle 3"
    },
    {
        ID: 5,
        TAG: "M:B",
        PARENT_TAG: "MAIN",
        TITLE: "B Title"
    },
    {
        ID: 6,
        TAG: "BS1",
        PARENT_TAG: "M:B",
        TITLE: "B Subtitle 1"
    },
    {
        ID: 7,
        TAG: "BS2",
        PARENT_TAG: "M:B",
        TITLE: "B Subtitle 2"
    },
    {
        ID: 8,
        TAG: "M:C",
        PARENT_TAG: "MAIN",
        TITLE: "C Title"
    },
    {
        ID: 8,
        TAG: "CS1",
        PARENT_TAG: "M:C",
        TITLE: "C Subtitle 1"
    }
]

function getMenu() {
    let grouped = _.groupBy(menuConfig, "PARENT_TAG");
    let menu = getItems(grouped.MAIN, grouped);
    console.log(JSON.stringify(menu, null, 3));
}

function getItems(items, grouped) {
    let subMenu = [];
    _.forEach(items, (item) => {
        let newItem = getItem(item, grouped)
        if (newItem) {
            subMenu.push(newItem);
        }
    });
    return subMenu;
}

function getItem(item, grouped) {
    if (grouped[item.TAG]) {
        let subMenu = getItems(grouped[item.TAG], grouped);
        if (subMenu && subMenu.length) {
            return {
                title: item.TITLE,
                subMenu: subMenu
            }
        }
    } else {
        let newItem = {
            title: item.TITLE
        }
        return newItem;
    }
}

getMenu();

Output needs to be like this;

[
  {
    "title": "A Title",
    "subMenu": [
      {
        "title": "A Subtitle 1"
      },
      {
        "title": "A Subtitle 2"
      },
      {
        "title": "A Subtitle 3"
      }
    ]
  },
  {
    "title": "B Title",
    "subMenu": [
      {
        "title": "B Subtitle 1"
      },
      {
        "title": "B Subtitle 2"
      }
    ]
  },
  {
    "title": "C Title",
    "subMenu": [
      {
        "title": "C Subtitle 1"
      }
    ]
  }
]

1 thought on “Creating a Navbar Menu from JSON data with Lodash”

  1. Here is the another solution with reduce:

    const menuConfig = [{
      ID: 1,TAG: "M:A", PARENT_TAG: "MAIN", TITLE: "A Title"
    }, {
      ID: 2, TAG: "AS1", PARENT_TAG: "M:A", TITLE: "A Subtitle 1"
    }, {
      ID: 3, TAG: "AS2", PARENT_TAG: "M:A", TITLE: "A Subtitle 2"
    }, {
      ID: 4, TAG: "AS3", PARENT_TAG: "M:A", TITLE: "A Subtitle 3"
    }, {
      ID: 5, TAG: "M:B", PARENT_TAG: "MAIN", TITLE: "B Title"
    }, {
      ID: 6, TAG: "BS1", PARENT_TAG: "M:B", TITLE: "B Subtitle 1"
    }, {
      ID: 7, TAG: "BS2", PARENT_TAG: "M:B", TITLE: "B Subtitle 2"
    }, {
      ID: 8, TAG: "M:C", PARENT_TAG: "MAIN", TITLE: "C Title"
    }, {
      ID: 8, TAG: "CS1", PARENT_TAG: "M:C", TITLE: "C Subtitle 1"
    }]
    
    function getMenu() {
      const menu = getItems(menuConfig, 'MAIN');
      console.log(menu);
    }
    
    function getItems(items, grandParentTag) {
      const newItems = items.reduce((modifiedObj, currentItem) => {
        const parentTag = currentItem.PARENT_TAG;
        const tag = currentItem.TAG;
    
        if (!modifiedObj[grandParentTag]) {
          modifiedObj[parentTag] = {};
        }
    
        if (!modifiedObj[grandParentTag][parentTag]) {
          modifiedObj[parentTag][tag] = {
            title: currentItem.TITLE,
            subMenu: [],
          };
        } else {
          modifiedObj[grandParentTag][parentTag].subMenu.push({
            title: currentItem.TITLE,
          });
        }
    
        return modifiedObj;
    
      }, {});
    
      return Object.values(newItems[grandParentTag]);
    }
    
    getMenu();
    
    Reply

Leave a Comment