1

I have a menu array called "items". It has submenus.

I need to filter the items with property "visible" equal 1. I don't know at run time how deep the hierarchy will be. I need a function returning a new array, with the next conditions:

  1. Every non-matching object with no children, or no matches in children hierarchy, should not exist in output object
  2. Every object with a descendant that contains a matching object, should remain
  3. Only descendants with matching objects should remain

My question is similar to this post Recursively filter array of objects.

But it does not work to me. I have used the following function, but it´s not working:

const items = [ { icon: "mdi-view-dashboard", title: "Dashboard", to: "/", visible: 1, }, 
{ title: "Manutenção", icon: "mdi-hammer-screwdriver", to: "", visible: 1, 
 items: [ 
    { title: "Usuários", icon: "mdi-account", to: "/usuarios", visible: 1, }, 
    { title: "Cores", to: "", visible: 1, 
     items: [ 
       { title: "Cores da Fila", icon: "mdi-eyedropper-variant", to: "/coresfila", visible: 1, },
       { title: "Cores da Agenda", icon: "mdi-palette", to: "/coresagenda", visible: 1, }, 
       ], 
     }, 
    { title: "Tabelas Médicas", to: "", visible: 1, 
     items: [ 
       { title: "Convênios", icon: "mdi-clipboard-outline", to: "/convenios", visible: 1, }, 
       { title: "Planos", icon: "mdi-plus-box", to: "/planos", visible: 1, }, 
       { title: "Especialidades", icon: "mdi-format-font", to: "/especialidadescompletas", visible: 1, }, 
       { title: "Modelos de Atestados", icon: "mdi-account-details-outline", to: "/modelosAtestados", visible: 1, }, 
       {  title: "Modelos de Prescrições", icon: "mdi-account-edit-outline",  to: "/modelosPrescricoes",  }, 
       { title: "Cid-10", icon: "mdi-alphabetical", to: "/cid10", visible: 1, }, 
       { title: "Procedimentos", icon: "mdi-alarm-plus", to: "/procedimentos", visible: 1, }, 
       { title: "Materiais", icon: "mdi-table-of-contents", to: "/materiais", visible: 1, },
       { title: "Medicamentos", icon: "mdi-water", to: "/medicamentos", visible: 1, }, 
       { title: "Taxas", icon: "mdi-cash-100", to: "/taxas", visible: 1, }, 
      ], 
    }, 
  ], 
}, 
{ title: "Empresa", icon: "mdi-cash-100", to: "", visible: 1, 
 items: [ { title: "Perfil da Empresa", icon: "mdi-account-network-outline", to: "/perfilempresa", visible: 1, }, 
 { title: "Créditos SMS", icon: "mdi-cash-usd-outline", to: "/creditossms", visible: 1, }, 
 ], 
}, 
{ title: "Clientes", icon: "mdi-account-alert-outline", to: "/clientes", visible: 1, }, 
{ title: "Agenda", icon: "far fa-calendar-check", to: "/agenda", visible: 1, }, 
{ title: "Fila", icon: "mdi-account-multiple-check", to: "/fila", visible: 1, }, 
{ title: "Atendimento Médico", icon: "fas fa-user-md", to: "/atendimento", visible: 1, }, 
{ title: "Tela de Chamadas", icon: "mdi-play-network-outline", to: "/telao", visible: 1, }, 
{ title: "DICOM", icon: "mdi-radioactive-off", to: "/dicom", visible: 1, }, 
{ title: "Estatísticas", icon: "mdi-chart-box", to: "", visible: 1, 
items: [ { title: "Clientes", icon: "mdi-account-arrow-right", to: "", visible: 1, 
 items: [ { title: "Por convênios", icon: "mdi-poll", to: "/estat_cliente_por_convenios", visible: 1, }, 
 { title: "Por mês", icon: "mdi-poll", to: "/estat_cliente_por_mes", visible: 1, }, 
 ], 
}, 
{ title: "Faturamento", icon: "mdi-cash-usd", to: "", visible: 1, 
 items: [ { title: "Por convênios", icon: "mdi-poll", to: "/estat_faturamento_por_convenios", visible: 1, }, 
 { title: "Por mês", icon: "mdi-poll", to: "/estat_faturamento_por_mes", visible: 1, }, 
], }, 
], }, 
{ title: "Autorizações", icon: "mdi-microphone-variant", to: "/listaautorizacoes", visible: 1, }, 
{ title: "Faturamento", icon: "mdi-cash-usd", to: "", visible: 1, 
items: [ { title: "Nova Guia", icon: "mdi-cart-plus", to: "/guiasfaturas", visible: 0, }, 
{ title: "Lista Guias", icon: "mdi-tray-plus", to: "/listaguias", visible: 1, }, 
{ title: "Lote de Guias", icon: "mdi-bag-personal", to: "/loteguias", visible: 1, }, ], }, 
] 


function ofilter(arr) {
  var matches = [];
  if (!Array.isArray(arr)) return matches;

  arr.forEach(function(i) {
    if (i.visible && i.visible === 1) {
      matches.push(i);
    } else {
      let childResults = this.ofilter(i.items);
      if (childResults.length)
        matches.push(Object.assign({}, i, {
          items: childResults
        }));
    }
  });
  return matches;
}
console.log(ofilter(items))

2
  • I tried to make you a snippet. Likely some issue with the object - please fix Commented Sep 8, 2020 at 13:56
  • Your object is not valid - please post a valid object without comments Commented Sep 8, 2020 at 14:06

2 Answers 2

1

Here's a recursive filter based on a recursive visibility check. This version preserves the nested structure:

const isVisible = item => item.visible
    || item.items?.some(isVisible)

const filterItems = items => {
    items.forEach(item => {
        if (item.items) item.items = filterItems(item.items)
    })

    return items.filter(isVisible)
}

console.log(filterItems(
    [
        { id: 'a', visible: 1 },
        { id: 'b', visible: 0 },
        {
            id: 'c',
            visible: 0,
            items: [
                { id: 'd', visible: 1 },
                { id: 'e', visible: 0 }
            ]
        },
        { id: 'f', visible: 1, items: [{ id: 'g', visible: 0 }] },
        { id: 'h', visible: 0, items: [{ id: 'i', visible: 0 }] },
    ]
))

Alternatively, here's a version that returns a flat array:

const filterItemsFlat = (items, results = []) => {
    items.forEach(item => {
        if (item.items) filterItemsFlat(item.items, results)
        if (item.visible) results.push(item)
    })

    results.forEach(r => delete r.items)

    return results
}

console.log(filterItemsFlat(
    [
        { id: 'a', visible: 1 },
        { id: 'b', visible: 0 },
        {
            id: 'c',
            visible: 0,
            items: [
                { id: 'd', visible: 1 },
                { id: 'e', visible: 0 }
            ]
        },
        { id: 'f', visible: 1, items: [{ id: 'g', visible: 0 }] },
        { id: 'h', visible: 0, items: [{ id: 'i', visible: 0 }] },
    ]
))

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

Comments

0

Another alternative to question:

 const items = [ 
  { icon: "mdi-view-dashboard", title: "Dashboard", to: "/", visible: 1, }, 
  { title: "Manutenção", icon: "mdi-hammer-screwdriver", to: "", visible: 0, 
   items: [ 
     { title: "Usuários", icon: "mdi-account", to: "/usuarios", visible: 1, }, 
     { title: "Cores", to: "", visible: 0}
   ]
  }
];

function ofilter(arr) {
  let r = [];     
  arr.forEach((i) => {
    if (i.visible == 1) {
      r.push(i);
    } 
    if (i.items) {  
      r.push(ofilter(i.items))
    }    
  })
  return r;
}

console.log('result:', ofilter(items))

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.