Home » vue » Recursively filter data for boolean key

Recursively filter data for boolean key

Posted by: admin November 26, 2021 Leave a comment

Questions:

My navigation gets the routes from the vue-router, so that I do not have to add them manually.

These routes have a meta boolean key called “inMenu”, as well as their child routes. I only manage to filter the parent routes but not the child routes.

var res = this.$router.options.routes.filter(function f(o) {
  if (o.route.meta.inMenu === true) return true

  if (o.children) {
    return (o.children = o.children.filter(f)).length
  }
})

This is how I filter the parent routes but I can’t manage it to filter the children.

return this.$router.options.routes.filter(route => route.meta.inMenu === true);

This is some sample data:

{
  "path": "/orders",
  "component": {
    "name": "Orders",
    "__file": "src/views/Orders.vue",
  },
  "meta": {
    "icon": "fa-history",
    "title": "Abwicklungen",
    "inMenu": true
  },
  "children": [
    {
      "path": "list",
      "name": "orderList",
      "component": {
        "name": "OrderList",
        "__file": "src/views/orders/list.vue",
      },
      "meta": {
        "title": "Bestellliste",
        "icon": "fa-circle-o",
        "inMenu": true
      }
    },
    {
      "path": "details/:id",
      "name": "orderDetails",
      "component": {
        "name": "OrderDetails",
        "__file": "src/views/orders/details.vue"
      },
      "meta": {
        "title": "Bestellung",
        "icon": "fa-circle-o",
        "inMenu": false
      }
    },
    {
      "path": "dailyclosing",
      "component": {
        "name": "OrderList",
        "__file": "src/views/orders/list.vue",
      },
      "meta": {
        "title": "Tagesabschluss",
        "icon": "fa-check",
        "inMenu": true
      }
    }
  ]
}

I want to have each route and children not shown if inMenu is false.

Answers:

Assuming you want all objects with true inMenu properties, you could build a new array with new children. Branches with no true inMenu items are filterd out.

function filter(array) {
    return array.reduce((r, { children = [], ...o }) => {
        children = filter(children);
        if (o.meta.inMenu || children.length) r.push(Object.assign({}, o, children.length && { children }));
        return r;
    }, [])
}

var data = [{ path: "/orders", meta: { icon: "fa-history", title: "Abwicklungen", inMenu: true }, children: [{ path: "list", name: "orderList", meta: { title: "Bestellliste", icon: "fa-circle-o", inMenu: true } }, { path: "details/:id", name: "orderDetails", meta: { title: "Bestellung", icon: "fa-circle-o", inMenu: false } }, { path: "dailyclosing", meta: { title: "Tagesabschluss", icon: "fa-check", inMenu: true } }] }, { path: "/orders", meta: { icon: "fa-history", title: "Abwicklungen", inMenu: false }, children: [{ path: "list", name: "orderList", meta: { title: "Bestellliste", icon: "fa-circle-o", inMenu: true } }, { path: "details/:id", name: "orderDetails", meta: { title: "Bestellung", icon: "fa-circle-o", inMenu: false } }, { path: "dailyclosing", meta: { title: "Tagesabschluss", icon: "fa-check", inMenu: true } }] }],
    result = filter(data);

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

###

I am assuming:

  1. You have multiple path objects inside an array.
  2. Each path object contains a root level meta key and a children key.
  3. If the inMenu value of the root meta key returns false, we filter out the whole object (which includes its children).
  4. children doesn’t contain any more children on its own .

So we apply reduce on the array, check whether the object’s root inMenu is true and if so it will reconstruct itself while filtering its children. Filtering the children happens via the short helper function.

var data = [{"path":"/orders","component":{"name":"Orders","__file":"src/views/Orders.vue",},"meta":{"icon":"fa-history","title":"Abwicklungen","inMenu":!0},"children":[{"path":"list","name":"orderList","component":{"name":"OrderList","__file":"src/views/orders/list.vue",},"meta":{"title":"Bestellliste","icon":"fa-circle-o","inMenu":!0}},{"path":"details/:id","name":"orderDetails","component":{"name":"OrderDetails","__file":"src/views/orders/details.vue"},"meta":{"title":"Bestellung","icon":"fa-circle-o","inMenu":!1}},{"path":"dailyclosing","component":{"name":"OrderList","__file":"src/views/orders/list.vue",},"meta":{"title":"Tagesabschluss","icon":"fa-check","inMenu":!0}}]}];

const f = arr => arr.filter(o => o.meta.inMenu);

let res = data.reduce((a,c) => (c.meta.inMenu && a.push({...c, children: f(c.children)}), a),[]);

console.log(res)

###

Here is a working snippet. I think you just need to update your function in a way I have changed it. Of-course I have not use vue.js routes here. This is just a sample. You need to update according to your need. I think you’ll get idea from here, about what is wrong in your function.

var data = [{
  "path": "/orders",
  "component": {
    "name": "Orders",
    "__file": "src/views/Orders.vue",
  },
  "meta": {
    "icon": "fa-history",
    "title": "Abwicklungen",
    "inMenu": true
  },
  "children": [
    {
      "path": "list",
      "name": "orderList",
      "component": {
        "name": "OrderList",
        "__file": "src/views/orders/list.vue",
      },
      "meta": {
        "title": "Bestellliste",
        "icon": "fa-circle-o",
        "inMenu": true
      }
    },
    {
      "path": "details/:id",
      "name": "orderDetails",
      "component": {
        "name": "OrderDetails",
        "__file": "src/views/orders/details.vue"
      },
      "meta": {
        "title": "Bestellung",
        "icon": "fa-circle-o",
        "inMenu": false
      }
    },
    {
      "path": "dailyclosing",
      "component": {
        "name": "OrderList",
        "__file": "src/views/orders/list.vue",
      },
      "meta": {
        "title": "Tagesabschluss",
        "icon": "fa-check",
        "inMenu": true
      }
    }
  ]
}];


var res = data.filter(function f(o) {
  if (o.children) {
    return (o.children = o.children.filter(f)).length
  }
  if (o.meta.inMenu === true) return true;
  return false;
})

console.log(res);