Home > Mobile >  Filter nested object based on deep value with Javascript
Filter nested object based on deep value with Javascript

Time:12-18

I have this nested object:

const menus = { 
    path: '/actions/step',
    icon: 'fa fa-wine-bottle',
    title: 'Fasi',
    children: [
      {
        path: '/actions/step/analysis',
        title: 'Analisi'
      },
      {
        path: '/actions/step/import',
        title: 'Importazione'
      },
      {
        path: '/actions/step/squeeze',
        title: 'Spremitura'
      },
      {
        path: '/actions/step/move',
        title: 'Spostamento'
      },
      {
        path: '/actions/step/splitauto',
        title: 'Travaso Guidato'
      },
      {
        path: '/actions/step/stir',
        title: 'Rimestaggio'
      },
      {
        path: '/actions/step/clarify',
        title: 'Chiarifica'
      },
      {
        path: '/actions/step/stabilization',
        title: 'Stabilizzazione'
      },
      {
        path: '/actions/step/bottling',
        title: 'Imbottigliamento'
      },
      {
        path: '/actions/step/clean',
        title: 'Pulizia'
      },
      {
        path: '/actions/step/clean_close',
        title: 'Pulizia e Chiusura'
      },
      {
        path: '/actions/step/add_product',
        title: 'Aggiunta Prodotto'
      },
    ]
  },
  {
    path: '/actions',
    icon: 'fa fa-tasks',
    title: 'Azioni',
    children: [
      {
        path: '/actions/type',
        title: 'Tipi di Azione'
      },
      {
        path: '/actions/list',
        title: 'Lista delle Azioni'
      },
      {
        path: '/actions/traceability',
        title: 'Tracciabilità'
      }
    ]
  },
  { 
    path: '/warehouse', 
    icon: 'fa fa-warehouse', 
    title: 'Magazzino',
    children: [
      {
        path: '/warehouse/list-warehouse-item',
        title: 'Lista Oggetti',
        children: [
          {
            path: '/warehouse/new-warehouse-item',
            title: 'Nuovo Oggetto'
          }
        ]
      },
    ]
  },
  { 
    path: '/suppliers', 
    icon: 'fa fa-truck', 
    title: 'Fornitori',
    children: [
      {
        path: '/suppliers/list-suppliers',
        title: 'Lista Fornitori',
        children: [
          {
            path: '/suppliers/new-supplier',
            title: 'Nuovo Fornitore'
          }
        ]
      }
    ]
  }

What I'm trying to achieve is to filter the nested object based on the path value.

So if I have /actions/step/import I would like to have this:

[{ 
    path: '/actions/step',
    icon: 'fa fa-wine-bottle',
    title: 'Fasi'
},
{
    path: '/actions/step/import',
    title: 'Importazione'
}]

Or in case /warehouse/new-warehouse-item I would have:

[{ 
    path: '/warehouse', 
    icon: 'fa fa-warehouse', 
    title: 'Magazzino'
},
{
    path: '/warehouse/list-warehouse-item',
    title: 'Lista Oggetti'
},
{
    path: '/warehouse/new-warehouse-item',
    title: 'Nuovo Oggetto'
}]

What I've tried to do is filtering like this way but it's incomplete (this.$router.history.current.path contains the string path):

menus.filter(menu => {
    if(menu.children){
        return menu.children.some(child => {
            if(child.children){
                return child.children.some(nephew => {
                    return nephew.path === this.$router.history.current.path;
                })
            } else {
                return child.path === this.$router.history.current.path;
            }
        })
    } else {
        return menu.path === this.$router.history.current.path;
    }
});

CodePudding user response:

The following recursive code gives the requested filtering. Please note that I included the given data "menus" in an Array for test purposes.

The cnt variable (int) is used for debugging purposes and indicates the level of recursion. It can be omitted.

The items variable (array of objects) is the initial array that contains the objects.

The target variable (string) is the desired path.

The sol variable (array of objects) is an initially empty array that will be populated with the paths that lead to the target.It must be cleared before any new call to itemFilter

        let cnt = 0 //For debugging only
        const itemFilter= function(items, target, cnt, sol ) {
            cnt  = 1
            for( let i = 0; i<items.length; i  ) {
                let item = items[i]
                if ( item.path == target) {
                    sol.push(item)
                    //console.log("DEBUG 1 : ", cnt, i, item.path, "Hit")
                    //console.log(sol)
                    return sol
                }
                //Otherwise...
                //console.log(cnt, i, item.path, "No hit")
                if (item.children) {
                    itemFilter(item.children, target, cnt, sol)
                    //console.log("DEBUG 2 : ", cnt, i)
                    //console.log(sol)
                    if (sol.length > 0) {
                        sol.push(item)
                        return sol
                    }
                }
                }
        }
        
        
        
    console.log("Suggested solution")    
    console.log("--------------------------------------------------------")
        let t = "/actions/step/import"
        console.log("CASE 1 : ", t)
        let filteredItems = []
        itemFilter(menus, t, 0, filteredItems)
        console.log(filteredItems)
        
        console.log("--------------------------------------------------------")
        t = "/warehouse/new-warehouse-item"
        console.log("CASE 2 : ", t)
        filteredItems = []
        itemFilter(menus, t, 0, filteredItems)
        console.log(filteredItems)
        
        console.log("--------------------------------------------------------")
        t = "/UNDEFINEDPATH/anything"
        console.log("CASE 3 : ", t)
        filteredItems = []
        itemFilter(menus, t, 0, filteredItems)
        console.log(filteredItems)




/*This is the console output (without debugging) : 

Suggested solution
--------------------------------------------------------
CASE 1 :  /actions/step/import
[ { path: '/actions/step/import', title: 'Importazione' },
  { path: '/actions/step',
    icon: 'fa fa-wine-bottle',
    title: 'Fasi',
    children:
     [ [Object],
       [Object],
       [Object],
       [Object],
       [Object],
       [Object],
       [Object],
       [Object],
       [Object],
       [Object],
       [Object],
       [Object] ] } ]
--------------------------------------------------------
CASE 2 :  /warehouse/new-warehouse-item
[ { path: '/warehouse/new-warehouse-item',
    title: 'Nuovo Oggetto' },
  { path: '/warehouse/list-warehouse-item',
    title: 'Lista Oggetti',
    children: [ [Object] ] },
  { path: '/warehouse',
    icon: 'fa fa-warehouse',
    title: 'Magazzino',
    children: [ [Object] ] } ]
--------------------------------------------------------
CASE 3 :  /UNDEFINEDPATH/anything
[]

*/

CodePudding user response:

Based on the excellent contribute of @Myrer, to omit the children object I edited his script like this:

const itemFilter = function(items, target, sol) {
   for(let i = 0; i < items.length; i  ) {
      let item = items[i];
      if (item.path === target) {
         const itemToPush = {
            path: item.path,
            title: item.title
         };

         if(item.icon){
            itemToPush['icon'] = item.icon;
         }

         sol.push(itemToPush);
         return sol;
      }

      if (item.children) {
         itemFilter(item.children, target, sol);
         if (sol.length > 0) {
            const itemToPush = {
               path: item.path,
               title: item.title
            };

            if(item.icon){
               itemToPush['icon'] = item.icon;
            }

            sol.push(itemToPush);
            return sol;
         }
      }
   }
}

let t = '/warehouse/new-warehouse-item';
let filteredItems = [];
itemFilter(this.menus, t, filteredItems);
console.log(filteredItems.reverse()); // Reversed the order of the array

// Output:
// [
//     {
//         "path": "/warehouse",
//         "title": "Magazzino",
//         "icon": "fa fa-warehouse"
//     },
//     {
//         "path": "/warehouse/list-warehouse-item",
//         "title": "Lista Oggetti"
//     },
//     {
//         "path": "/warehouse/new-warehouse-item",
//         "title": "Nuovo Oggetto"
//     }
// ]
  • Related