Дерево json «Меню» с вложенными элементами: отметьте «Ветка» - PullRequest
0 голосов
/ 22 марта 2019

У меня есть это дерево JSON, которое представляет меню:

var menus = [
  {
    label : "1",
    items: [
      {
        label : "1.1"
      },
      {
        label : "1.2",
        items : [
          {
            label : "1.2.1"
          },
          {
            label : "1.2.2"
          }
        ]
      },
      {
        label : "1.3"
      },
    ]
  },
  {
    label : "2"
  }
]

Я хочу изменить этот JSON, добавив для каждого элемента свойство selected .Это свойство, логическое, будет установлено в true , если метка является правильной, или , это сложная часть , если правая сторона - потомок.Например, если я ищу метку 1.2, будут выбраны все метки 1 и 1.2.Поэтому я получу этот JSON:

var menus = [
  {
    label : "1",
    selected : true,
    items: [
      {
        label : "1.1"
        selected : false
      },
      {
        label : "1.2",
        selected : true,
        items : [
          {
            label : "1.2.1"
            selected : false
          },
          {
            label : "1.2.2",
            selected : false
          }
        ]
      },
      {
        label : "1.3",
        selected : false
      },
    ]
  },
  {
    label : "2",
    selected : false
  }
]

selected : false не является необходимым.Lodash для меня в порядке;)!

Есть предложения?

edit: где я!-> https://codepen.io/anon/pen/XGoXjM?editors=0010

edit 2: поиск элементов не должен основываться на том, как я написал метки.На этикетках может быть любая строка ... Извините ...

Спасибо

Ответы [ 3 ]

2 голосов
/ 22 марта 2019

Это решение использует цикл for для рекурсивной итерации пунктов меню и их дочерних элементов. Если элемент selected, он добавляет selected: true к элементу и его родителям:

const selectMenuItems = menus => selectedLabel => {  
  const internal = arr => {
    let selected = false

    for(let i = 0; i < arr.length; i++) {
      const item = arr[i]
      const childrenSelected = !!item.items && internal(item.items)
      item.selected = childrenSelected || item.label === selectedLabel
      selected = selected || item.selected
    }
    
    return selected
  }
  
  internal(menus)
  
  return menus
}

const menus = [{"label":"1","items":[{"label":"1.1"},{"label":"1.2","items":[{"label":"1.2.1"},{"label":"1.2.2"}]},{"label":"1.3"}]},{"label":"2"}]

const menuSelector = selectMenuItems(menus)

const result = menuSelector('1.2')

console.log(result)
.as-console-wrapper { top: 0; max-height: 100% !important; }
0 голосов
/ 22 марта 2019

Я бы просто проверил метки следующим образом:

var menus = [{
        label: "1",
        items: [{
                label: "1.1"
            },
            {
                label: "1.2",
                items: [{
                        label: "1.2.1"
                    },
                    {
                        label: "1.2.2"
                    }
                ]
            },
            {
                label: "1.3"
            },
        ]
    },
    {
        label: "2"
    }
];

var checkSelected = function(items, search) {
    for (var key in items) {
        items[key].selected = search.startsWith(items[key].label) && items[key].label.length<=search.length;
        if (items[key].items) {
            checkSelected(items[key].items, search);
        };
    };
};

var test = "1.2";
checkSelected(menus, test);
console.log(menus);

Также на JSFiddle .

Метод startWith () определяет, начинается ли строка с символы указанной строки, возвращающие true или false как необходимо.

цитата отсюда

0 голосов
/ 22 марта 2019

Вы можете использовать некоторый рекурсивный подход для реализации этого.

let str = '1.2.1';


function checkItem(arr, strArr) {
  // iterate over the array
  arr.forEach((obj) => {
    // set selected property based on matching every digit in label in same order
    // if digits would be single then you can use startsWith and no need to split string
    obj.selected = obj.label.split('.').every((it, i) => it === strArr[i]);
    // if nested item is there then call recursively
    obj.items && checkItem(obj.items, strArr);
  });
  return arr;
}

checkItem(menus, str.split('.'));

var menus = [{
    label: "1",
    items: [{
        label: "1.1"
      },
      {
        label: "1.2",
        items: [{
            label: "1.2.1"
          },
          {
            label: "1.2.2"
          }
        ]
      },
      {
        label: "1.3"
      },
    ]
  },
  {
    label: "2"
  }
];



let str = '1.2.1';


function checkItem(arr, strArr) {
  arr.forEach((obj) => {
    obj.selected = obj.label.split('.').every((it, i) => it === strArr[i]);
    obj.items && checkItem(obj.items, strArr);
  });
  return arr;
}

checkItem(menus, str.split('.'));


console.log(menus);

UPADATE: Поскольку вы хотите обновить выбранное свойство полностью независимо от метки, вы можете сделать что-то вроде следующего.Я предполагаю, что вы хотите обновить в зависимости от позиции в массиве.

let str = '1.2.1';


function checkItem(arr, prefixArray, strArr) {
  // iterate over the array
  arr.forEach((obj, i) => {
    // generate new prefix array for checking
    let pa = [...prefixArray, i + 1];
    // compare prefix array with the string array to check matches
    obj.selected = pa.every((it, i) => it == strArr[i]);
    // if items defined do it recursively
    obj.items && checkItem(obj.items, pa, strArr);
  });
  return arr;
}

checkItem(menus,[], str.split('.'));

var menus = [{
    label: "1",
    items: [{
        label: "1.1"
      },
      {
        label: "1.2",
        items: [{
            label: "1.2.1"
          },
          {
            label: "1.2.2"
          }
        ]
      },
      {
        label: "1.3"
      },
    ]
  },
  {
    label: "2"
  }
];



let str = '1.2.1';


function checkItem(arr, prefixArray, strArr) {
  arr.forEach((obj, i) => {
    let pa = [...prefixArray, i + 1];
    obj.selected = pa.every((it, i) => it == strArr[i]);
    obj.items && checkItem(obj.items, pa, strArr);
  });
  return arr;
}

checkItem(menus,[], str.split('.'));


console.log(menus);
...