Vuejs группировка флажков выбрать все - PullRequest
1 голос
/ 14 июля 2020

У меня есть массив объектов, разделенных на группы. каждая группа имеет свои собственные элементы, и мне нужно установить все флажки для детей, если отмечены родители, и снять флажок, если родители не отмечены. также, если selectAll отмечен, все группы и элементы групп должны быть отмечены

то, что я хочу достичь, совпадает с этим примером

selectall.gif

У меня здесь установлена ​​ jsfiddle , и это то, что я сделал до сих пор.

Data

const groups = [
   {
      id: 1,
      name: "TEST A",
      items: [
         { id: 1, name: "item 1" },
         { id: 2, name: "item 2" }
      ]
   },
   {
      id: 2,
      name: "TEST B",
      items: [
         { id: 3, name: "item 1" },
         { id: 4, name: "item 2" }
      ]
   }
]

HTML

<div id="app">
  <div>
    
    <input type="checkbox" class="mb-2" v-model="selectAll" /> select all
    
    <div v-for="group in groups" :key="group.id" class="mb-2">

      <input
        type="checkbox"
        v-model="selectedGroups"
        :value="group.id"
      />
      
      <b>{{ group.name }}</b>

      <c-item 
        v-for="item in group.items"
        :item="item"
        :key="item.id"
        @change="onChangeItem"
        :checked="selectedItems.includes(item.id)"
      />

    </div>
    
  </div>
</div>

<template id="x-item">
  <div>
  
    <input 
     type="checkbox"
     @change="$emit('change', item.id, $event)"
     :value="item.id"
     :checked="checked"
    />
    {{ item.name }}
    
  </div>
</template>

JS

Vue.component('c-item', {
    props: ['item', 'checked'],
  template: "#x-item",
})

new Vue({
  el: "#app",
  data: {
    selectedItems: [],
    selectedGroups: [],
    groups: [
       {
          id: 1,
          name: "TEST A",
          items: [
             { id: 1, name: "item 1" },
             { id: 2, name: "item 2" }
          ]
       },
       {
          id: 2,
          name: "TEST B",
          items: [
             { id: 3, name: "item 1" },
             { id: 4, name: "item 2" }
          ]
       }
    ]
  },
  methods: {
        onChangeItem(itemId, $event) {
      if ($event.target.checked) this.selectedItems.push(itemId);
      else {
        const index = this.selectedItems.findIndex(c => c === itemId);
        if (index >= 0) this.selectedItems.splice(index, 1);
      }
    }
  },
  computed: {
    selectAll: {
      get() {
        return this.groups
          ? this.selectedGroups.length == this.groups.length
          : false;
      },
      set(value) {
        let selectedGroups = [];

        if (value) {
          this.groups.forEach(function(item) {
            selectedGroups.push(item.id);
          });
        }

        this.selectedGroups = selectedGroups;
      }
    }
  }
})

Кто-нибудь может мне помочь? Заранее спасибо!

Ответы [ 2 ]

1 голос
/ 15 июля 2020

Как правило, вы можете решить эту проблему с помощью рекурсивного компонента. Концепция состоит в том, чтобы построить дерево объектов и на любом узле, когда отмечено изменение, затем вызвать обновление родительского и дочернего элементов, и изменения будут go рекурсивно.

<template id='x-item'>
  <div>
    <label>
      <input
        type='checkbox'
        :checked='item.checked'
        @change='onChange($event.target.checked)'>
      <span>{{ item.label }}</span>
    </label>
    <template v-if='item.children'>
      <x-item
        v-for='item in item.children'
        ref='children'
        :item='item'
        @change='onChildChange'>
      </x-item>
    </template>
  </div>
</template>
Vue.component('x-item', {
  template: '#x-item',
  props: ['item'],
  methods: {
    onChange(checked) {
      this.item.checked = checked
      this.updateParent()
      this.updateChildren(checked)
    },
    onChildChange() {
      this.item.checked = this.$refs.children
        .every(child => child.item.checked)
      this.updateParent()
    },
    updateParent() {
      this.$emit('change')
    },
    updateChildren(checked) {
      if (!this.item.children) return
      this.$refs.children.forEach(child => {
        child.item.checked = checked
        child.updateChildren(checked)
      })
    }
  }
})

Пример

Иногда рекурсивный компонент может быть нелегко стилизовать, если форма не динамическая c вы также можете сделать итеративную.

<div id='app'>
  <template v-if='root'>
    <x-item :item='root' @change='onChange'></x-item>
    <div v-for='group in root.children'>
      <x-item :item='group' @change='onChange'></x-item>
      <div v-for='item in group.children'>
        <x-item :item='item' @change='onChange'></x-item>
      </div>
    </div>
  </template>
</div>

<template id='x-item'>
  <label>
    <input
      type='checkbox'
      :checked='item.checked'
      @change='$emit("change", item, $event.target.checked)'>
    <span>{{ item.name }}</span>
  </label>
</template>
...
  methods: {
    onChange(node, checked) {
      node.checked = checked
      this.updateChildren(node, checked)
      this.updateTree()
    },
    updateChildren(node, checked) {
      if (!node.children) return
      node.children.forEach(child => {
        child.checked = checked
        this.updateChildren(child, checked)
      })
    },
    updateTree() {
      (function update(node) {
        if (!node.children) return
        node.children.forEach(update)
        node.checked = node.children.every(child => child.checked)
      })(this.root)
    }
  }
...

Пример

0 голосов
/ 15 июля 2020

Вы можете определить selectAll сеттер следующим образом:


      set(value) {
        // optionally, if value is false then unselect all
        if (!value) {
            this.selectedGroups = [];
            this.selectedItems = [];
            return;
        }
        // otherwise, select all
        this.selectedGroups = this.groups.map(group => group.id);
        this.selectedItems = this.groups
          .map(group => group.items)
           // java flatMap equivalent
           // converts 2 dimensional array ([[], []]) into 1 dimensional array ([])
          .reduce((all, next) => all.concat(next), [])
          .map(item => item.id)
      }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...