Ian White
Ian White

Reputation: 27

Recreate an object from an array of objects in Javascript

I could use some help with the following:

I'm trying to create a filterable wordpress nav menu using React Tree Menu.

The Tree Menu component requires the following data structure:

{
    "Home" : {
      checkbox: false,
      ID: 1,
      children: {
        "Getting Started" : {
          checkbox: false,
          ID: 47,
          slug: 'getting-started',
        },
        "Interaction Design Principles": {
          checkbox: false,
          children: {
            "Design Principle the First" : {
              selected: false,
              checkbox: false,
              ID: 67
            }
          }
        }
      }
    },
    "UPS Mobile (iOs, Android)" : {
      checkbox: false,
      children: {
        "Overview" : {
          checkbox: false,
          ID: 22
        },
        "Reference" : {
          checkbox: false,
          ID: 14
        }
      }
    },
    "mDot" : {
      checkbox: false,
      children: {
        "Elements" : {
          checkbox: false,
          ID: 19,
          children: {
            "Navigation" : {
              checkbox: false,
              ID: 90
            }
          }
        },
      }
    }
  }

I have set up parent and child pages of the above in wordpress and have also created a hierarchical wordpress menu. I am using the wordpress menu api

which returns the following data structure:

[
  {
    "ID": 46,
    "order": 1,
    "parent": 0,
    "title": "Home",
    "attr": "",
    "target": "",
    "classes": "",
    "xfn": "",
    "description": "",
    "object_id": 2,
    "object": "page",
    "type": "post_type",
    "type_label": "Page",
    "children": [
      {
        "ID": 47,
        "order": 2,
        "parent": 46,
        "title": "Getting Started",
        "url": "http://mobilestyle.ups.dev/home/getting-started/",
        "attr": "",
        "target": "",
        "classes": "",
        "xfn": "",
        "description": "",
        "object_id": 15,
        "object": "page",
        "type": "post_type",
        "type_label": "Page",
        "children": []
      },
      {
        "ID": 48,
        "order": 3,
        "parent": 46,
        "title": "Interaction Design Principles",
        "url": "http://mobilestyle.ups.dev/home/interaction-design-principles/",
        "attr": "",
        "target": "",
        "classes": "",
        "xfn": "",
        "description": "",
        "object_id": 22,
        "object": "page",
        "type": "post_type",
        "type_label": "Page",
        "children": [
          {
            "ID": 49,
            "order": 4,
            "parent": 48,
            "title": "Design Principle the First",
            "url": "http://mobilestyle.ups.dev/home/interaction-design-principles/design-principle-the-first/",
            "attr": "",
            "target": "",
            "classes": "",
            "xfn": "",
            "description": "",
            "object_id": 24,
            "object": "page",
            "type": "post_type",
            "type_label": "Page",
            "children": []
          }
        ]
      }
    ]
  },
  {
    "ID": 50,
    "order": 5,
    "parent": 0,
    "title": "mDot",
    "url": "http://mobilestyle.ups.dev/mdot/",
    "attr": "",
    "target": "",
    "classes": "",
    "xfn": "",
    "description": "",
    "object_id": 8,
    "object": "page",
    "type": "post_type",
    "type_label": "Page",
    "children": [
      {
        "ID": 51,
        "order": 6,
        "parent": 50,
        "title": "Elements",
        "url": "http://mobilestyle.ups.dev/mdot/elements/",
        "attr": "",
        "target": "",
        "classes": "",
        "xfn": "",
        "description": "",
        "object_id": 30,
        "object": "page",
        "type": "post_type",
        "type_label": "Page",
        "children": [
          {
            "ID": 52,
            "order": 7,
            "parent": 51,
            "title": "Navigation",
            "url": "http://mobilestyle.ups.dev/mdot/elements/navigation/",
            "attr": "",
            "target": "",
            "classes": "",
            "xfn": "",
            "description": "",
            "object_id": 32,
            "object": "page",
            "type": "post_type",
            "type_label": "Page",
            "children": []
          }
        ]
      }
    ]
  },
  {
    "ID": 54,
    "order": 8,
    "parent": 0,
    "title": "UPS Mobile (iOS, Android)",
    "url": "http://mobilestyle.ups.dev/ups-mobile/",
    "attr": "",
    "target": "",
    "classes": "",
    "xfn": "",
    "description": "",
    "object_id": 13,
    "object": "page",
    "type": "post_type",
    "type_label": "Page",
    "children": [
      {
        "ID": 55,
        "order": 9,
        "parent": 54,
        "title": "Overview",
        "url": "http://mobilestyle.ups.dev/ups-mobile/overview/",
        "attr": "",
        "target": "",
        "classes": "",
        "xfn": "",
        "description": "",
        "object_id": 26,
        "object": "page",
        "type": "post_type",
        "type_label": "Page",
        "children": []
      },
      {
        "ID": 56,
        "order": 10,
        "parent": 54,
        "title": "Reference",
        "url": "http://mobilestyle.ups.dev/ups-mobile/reference/",
        "attr": "",
        "target": "",
        "classes": "",
        "xfn": "",
        "description": "",
        "object_id": 28,
        "object": "page",
        "type": "post_type",
        "type_label": "Page",
        "children": []
      }
    ]
  }
]

Can someone please help me turn what I receive from the wordpress menu api into what the Tree Menu component expects?

Thanks in advance for any help. -Ian

Upvotes: 2

Views: 691

Answers (2)

Scott Sauyet
Scott Sauyet

Reputation: 50797

Here's a pretty simple recursive version:

const buildMenu = (xs) =>
  xs .reduce ((a, {title, ID, children}) => ((a [title] = {
    checkbox: false, ID, ... (children .length ? {children: buildMenu (children)} : {})
  }), a), {})

const source = [{ID: 46, order: 1, parent: 0, title: "Home", attr: "", target: "", classes: "", xfn: "", description: "", object_id: 2, object: "page", type: "post_type", type_label: "Page", children: [{ID: 47, order: 2, parent: 46, title: "Getting Started", url: "http://mobilestyle.ups.dev/home/getting-started/", attr: "", target: "", classes: "", xfn: "", description: "", object_id: 15, object: "page", type: "post_type", type_label: "Page", children: []}, {ID: 48, order: 3, parent: 46, title: "Interaction Design Principles", url: "http://mobilestyle.ups.dev/home/interaction-design-principles/", attr: "", target: "", classes: "", xfn: "", description: "", object_id: 22, object: "page", type: "post_type", type_label: "Page", children: [{ID: 49, order: 4, parent: 48, title: "Design Principle the First", url: "http://mobilestyle.ups.dev/home/interaction-design-principles/design-principle-the-first/", attr: "", target: "", classes: "", xfn: "", description: "", object_id: 24, object: "page", type: "post_type", type_label: "Page", children: []}]}]}, {ID: 50, order: 5, parent: 0, title: "mDot", url: "http://mobilestyle.ups.dev/mdot/", attr: "", target: "", classes: "", xfn: "", description: "", object_id: 8, object: "page", type: "post_type", type_label: "Page", children: [{ID: 51, order: 6, parent: 50, title: "Elements", url: "http://mobilestyle.ups.dev/mdot/elements/", attr: "", target: "", classes: "", xfn: "", description: "", object_id: 30, object: "page", type: "post_type", type_label: "Page", children: [{ID: 52, order: 7, parent: 51, title: "Navigation", url: "http://mobilestyle.ups.dev/mdot/elements/navigation/", attr: "", target: "", classes: "", xfn: "", description: "", object_id: 32, object: "page", type: "post_type", type_label: "Page", children: []}]}]}, {ID: 54, order: 8, parent: 0, title: "UPS Mobile (iOS,  Android)", url: "http://mobilestyle.ups.dev/ups-mobile/", attr: "", target: "", classes: "", xfn: "", description: "", object_id: 13, object: "page", type: "post_type", type_label: "Page", children: [{ID: 55, order: 9, parent: 54, title: "Overview", url: "http://mobilestyle.ups.dev/ups-mobile/overview/", attr: "", target: "", classes: "", xfn: "", description: "", object_id: 26, object: "page", type: "post_type", type_label: "Page", children: []}, {ID: 56, order: 10, parent: 54, title: "Reference", url: "http://mobilestyle.ups.dev/ups-mobile/reference/", attr: "", target: "", classes: "", xfn: "", description: "", object_id: 28, object: "page", type: "post_type", type_label: "Page", children: []}]}]

console .log (buildMenu (source))
.as-console-wrapper {max-height: 100% !important; top: 0}

We fold our array into an object, adding the property of the current title with a simple value consisting of the ID, an arbitrarily false checkbox attribute (is this actually derivable from the input?) and -- if our node has children -- the result of recurring on those children.

Upvotes: 0

Dave
Dave

Reputation: 10924

I'd use a recursive function to build the object you want. Something like the following:

function buildMenu(source, result) {
  //build a return value if one wasn't passed in
  result = result || {};
  
  if (source && source.length) {
    
    var item = source.shift(); //take first item from the array
    result[item.title] = { ID : item.ID }; //make a new property in the result

    //if there are children, build them recursively
    if (item.children && item.children.length) {
      result[item.title].children = buildMenu(item.children);
    }
    
    //build additional items recursively, based on the remaining items in the array
    return buildMenu(source, result);
    
  } else {
    //none left, done
    return result;
  }
}

Call that function on your source array and it should work. There's a running example below if you want to try it out.

function buildMenu(source, result) {
  result = result || {};
  
  if (source && source.length) {
    
    var item = source.shift();
    result[item.title] = { ID : item.ID };
    
    if (item.children && item.children.length) {
      result[item.title].children = buildMenu(item.children);
    }
    
    return buildMenu(source, result);
    
  } else {
    return result;  
  }
}

var source = [
  {
    "ID": 46,
    "order": 1,
    "parent": 0,
    "title": "Home",
    "attr": "",
    "target": "",
    "classes": "",
    "xfn": "",
    "description": "",
    "object_id": 2,
    "object": "page",
    "type": "post_type",
    "type_label": "Page",
    "children": [
      {
        "ID": 47,
        "order": 2,
        "parent": 46,
        "title": "Getting Started",
        "url": "http://mobilestyle.ups.dev/home/getting-started/",
        "attr": "",
        "target": "",
        "classes": "",
        "xfn": "",
        "description": "",
        "object_id": 15,
        "object": "page",
        "type": "post_type",
        "type_label": "Page",
        "children": []
      },
      {
        "ID": 48,
        "order": 3,
        "parent": 46,
        "title": "Interaction Design Principles",
        "url": "http://mobilestyle.ups.dev/home/interaction-design-principles/",
        "attr": "",
        "target": "",
        "classes": "",
        "xfn": "",
        "description": "",
        "object_id": 22,
        "object": "page",
        "type": "post_type",
        "type_label": "Page",
        "children": [
          {
            "ID": 49,
            "order": 4,
            "parent": 48,
            "title": "Design Principle the First",
            "url": "http://mobilestyle.ups.dev/home/interaction-design-principles/design-principle-the-first/",
            "attr": "",
            "target": "",
            "classes": "",
            "xfn": "",
            "description": "",
            "object_id": 24,
            "object": "page",
            "type": "post_type",
            "type_label": "Page",
            "children": []
          }
        ]
      }
    ]
  },
  {
    "ID": 50,
    "order": 5,
    "parent": 0,
    "title": "mDot",
    "url": "http://mobilestyle.ups.dev/mdot/",
    "attr": "",
    "target": "",
    "classes": "",
    "xfn": "",
    "description": "",
    "object_id": 8,
    "object": "page",
    "type": "post_type",
    "type_label": "Page",
    "children": [
      {
        "ID": 51,
        "order": 6,
        "parent": 50,
        "title": "Elements",
        "url": "http://mobilestyle.ups.dev/mdot/elements/",
        "attr": "",
        "target": "",
        "classes": "",
        "xfn": "",
        "description": "",
        "object_id": 30,
        "object": "page",
        "type": "post_type",
        "type_label": "Page",
        "children": [
          {
            "ID": 52,
            "order": 7,
            "parent": 51,
            "title": "Navigation",
            "url": "http://mobilestyle.ups.dev/mdot/elements/navigation/",
            "attr": "",
            "target": "",
            "classes": "",
            "xfn": "",
            "description": "",
            "object_id": 32,
            "object": "page",
            "type": "post_type",
            "type_label": "Page",
            "children": []
          }
        ]
      }
    ]
  },
  {
    "ID": 54,
    "order": 8,
    "parent": 0,
    "title": "UPS Mobile (iOS, Android)",
    "url": "http://mobilestyle.ups.dev/ups-mobile/",
    "attr": "",
    "target": "",
    "classes": "",
    "xfn": "",
    "description": "",
    "object_id": 13,
    "object": "page",
    "type": "post_type",
    "type_label": "Page",
    "children": [
      {
        "ID": 55,
        "order": 9,
        "parent": 54,
        "title": "Overview",
        "url": "http://mobilestyle.ups.dev/ups-mobile/overview/",
        "attr": "",
        "target": "",
        "classes": "",
        "xfn": "",
        "description": "",
        "object_id": 26,
        "object": "page",
        "type": "post_type",
        "type_label": "Page",
        "children": []
      },
      {
        "ID": 56,
        "order": 10,
        "parent": 54,
        "title": "Reference",
        "url": "http://mobilestyle.ups.dev/ups-mobile/reference/",
        "attr": "",
        "target": "",
        "classes": "",
        "xfn": "",
        "description": "",
        "object_id": 28,
        "object": "page",
        "type": "post_type",
        "type_label": "Page",
        "children": []
      }
    ]
  }
];

var dest = buildMenu(source);
console.log(dest);

Upvotes: 3

Related Questions