Удалить выбранную строку таблицы VueJS? - PullRequest
0 голосов
/ 29 апреля 2020

Я использую таблицу данных Vuetify и визуализирую заголовки и реквизиты элементов с помощью Vuex. Я хочу удалить только те строки / строки, которые были выбраны. Я настроил метод deleteRow, но сейчас он, кажется, удаляет последнюю строку по умолчанию.

См. Это работает CodeSandbox .

Это компонент таблицы: -

<template>
  <div>
    <v-data-table
      v-model="selected"
      :headers="getHeaders"
      :items="getDesserts"
      hide-actions
      select-all
      item-key="name"
    >
      <template v-slot:headers="props">
        <tr>
          <th>
            <v-checkbox
              :input-value="props.all"
              :indeterminate="props.indeterminate"
              primary
              hide-details
              @click.stop="toggleAll"
            ></v-checkbox>
          </th>
          <th v-for="header in props.headers" :key="header.text">
            <v-icon small>arrow_upward</v-icon>
            {{ header.text }}
          </th>
        </tr>
      </template>
      <template v-slot:items="props">
        <tr :active="props.selected" @click="props.selected = !props.selected">
          <td>
            <v-checkbox :input-value="props.selected" primary hide-details></v-checkbox>
          </td>
          <td>{{ props.item.name }}</td>
          <td>{{ props.item.calories }}</td>
          <td>{{ props.item.fat }}</td>
        </tr>
      </template>
    </v-data-table>
    <v-btn @click="deleteRow">Delete Selected</v-btn>
  </div>
</template>

<script>
import { mapGetters, mapMutations } from "vuex";
export default {
  name: "HelloWorld",
  data() {
    return {
      selected: []
    };
  },
  computed: {
    ...mapGetters({
      getHeaders: "getHeaders",
      getDesserts: "getDesserts"
    })
  },
  methods: {
    ...mapMutations({
      deleteRow: "deleteRow"
    }),
    toggleAll() {
      if (this.selected.length) this.selected = [];
      else this.selected = this.getDesserts.slice();
    }
  }
};
</script>

А это мой магазин Vuex: -

import Vue from "vue";
import Vuex from "vuex";

Vue.use(Vuex);

export default new Vuex.Store({
  state: {
    headers: [
      {
        text: "Dessert (100g serving)",
        align: "left",
        value: "name"
      },
      { text: "Calories", value: "calories" },
      { text: "Fat (g)", value: "fat" }
    ],
    desserts: [
      {
        value: false,
        name: "Lollipop",
        calories: 159,
        fat: 6.0
      },
      {
        value: false,
        name: "Marshamallow",
        calories: 262,
        fat: 16.0
      }
    ]
  },
  getters: {
    getHeaders: state => state.headers,
    getDesserts: state => state.desserts
  },
  mutations: {
    deleteRow(state, name) {
      let index = state.desserts.findIndex(el => el.name === name);
      state.desserts.splice(index, 1);
    }
  }
});

Ответы [ 3 ]

2 голосов
/ 29 апреля 2020

Вам просто нужно 2 простых изменения ...

1. изменить мутацию Vuex:

  mutations: {
    deleteRow(state, selected) {
      state.desserts = state.desserts.filter(el => !selected.includes(el));
    }
  }

2. обновите @, чтобы передать selected:

  <v-btn @click="deleteRow(selected)">Delete Selected</v-btn>

Рабочая демонстрация: https://codeply.com/p/e0kSBOhyUE

коды и поле

1 голос
/ 29 апреля 2020

Вы должны исправить две точки. В вашем шаблоне HTML вы должны исправить это:

<v-btn @click="deleteRow(selected)">Delete Selected</v-btn>

И вы должны исправить свою мутацию:

mutations: {
  deleteRow(state, selectedRows) {
    for (let row of selectedRows) {
      let index = state.desserts.findIndex(el => el.name === row.name);
      state.desserts.splice(index, 1);
    }
  },
},

Я опубликую весь код, если у вас есть сомнения.

<template>
  <div>
    <v-data-table
      v-model="selected"
      :headers="getHeaders"
      :items="getDesserts"
      hide-actions
      select-all
      item-key="name"
    >
      <template v-slot:headers="props">
        <tr>
          <th>
            <v-checkbox
              :input-value="props.all"
              :indeterminate="props.indeterminate"
              primary
              hide-details
              @click.stop="toggleAll"
            ></v-checkbox>
          </th>
          <th v-for="header in props.headers" :key="header.text">
            <v-icon small>arrow_upward</v-icon>
            {{ header.text }}
          </th>
        </tr>
      </template>
      <template v-slot:items="props">
        <tr :active="props.selected" @click="props.selected = !props.selected">
          <td>
            <v-checkbox :input-value="props.selected" primary hide-details></v-checkbox>
          </td>
          <td>{{ props.item.name }}</td>
          <td>{{ props.item.calories }}</td>
          <td>{{ props.item.fat }}</td>
        </tr>
      </template>
    </v-data-table>
    <v-btn @click="deleteRow(selected)">Delete Selected</v-btn>
  </div>
</template>

<script>
import { mapGetters, mapMutations } from 'vuex';
export default {
  name: 'HelloWorld',
  data() {
    return {
      selected: [],
    };
  },
  computed: {
    ...mapGetters({
      getHeaders: 'getHeaders',
      getDesserts: 'getDesserts',
    }),
  },
  methods: {
    ...mapMutations({
      deleteRow: 'deleteRow',
    }),
    toggleAll() {
      if (this.selected.length) this.selected = [];
      else this.selected = this.getDesserts.slice();
    },
  },
};
</script>
import Vue from 'vue';
import Vuex from 'vuex';

Vue.use(Vuex);

export default new Vuex.Store({
  state: {
    headers: [
      { text: 'Dessert (100g serving)', align: 'left', value: 'name' },
      { text: 'Calories', value: 'calories' },
      { text: 'Fat (g)', value: 'fat' },
    ],
    desserts: [
      { value: false, name: 'Lollipop', calories: 159, fat: 6.0 },
      { value: false, name: 'Marshamallow', calories: 262, fat: 16.0 },
    ],
  },
  getters: {
    getHeaders: state => state.headers,
    getDesserts: state => state.desserts,
  },
  mutations: {
    deleteRow(state, selectedRows) {
      for (let row of selectedRows) {
        let index = state.desserts.findIndex(el => el.name === row.name);
        state.desserts.splice(index, 1);
      }
    },
  },
  actions: {},
  modules: {},
});

0 голосов
/ 29 апреля 2020

Вы не передаете выбранное имя мутациям. По этой причине приведенный ниже код вернет -1 и, таким образом, удалит последний элемент из массива.

//In HelloWorld.vue, name is not passed to function
<v-btn @click="deleteRow">Delete Selected</v-btn>
//name is not passed to the state.
deleteRow(state, name) {
  let index = state.desserts.findIndex(el => el.name === name);
  console.log(index) //will log -1   
  state.desserts.splice(index, 1);
}

Быстрое решение - передача имени из источника

<v-btn @click="deleteRow(selected[0].name)">Delete Selected</v-btn>

Но при этом будет удален только один элемент из selected, где выбранным является массив элементов, которые выбираются из таблицы. И ожидаемое поведение - все выбранные элементы будут удалены из массива. Либо вы можете передать все выбранные элементы в функцию удаления строк как deleteRow(selected), либо вы можете изменить свой магазин для записи выбранных элементов.

state: {
  headers: {...},
  desserts: {...},
  selected: []
},
mutations: {
  setSelected(state, items){
    state.selected = items;
  },
  deleteRow(state, name) {
    const selectedItems = state.selected
    for(var i=0;i<selectedItems.length;i++){
      let index = state.desserts.findIndex(el => el.name === selectedItems[i]);
      state.desserts.splice(index, 1);
    }
  }
}

И в вашем HelloWorld. vue

<template>
  <div>
    <v-data-table
      v-model="selected"
      :headers="getHeaders"
      :items="getDesserts"
      hide-actions
      select-all
      item-key="name"
    >
      <template v-slot:headers="props">
        <tr>
          <th>
            <v-checkbox
              :input-value="props.all"
              :indeterminate="props.indeterminate"
              primary
              hide-details
              @click.stop="toggleAll"
            ></v-checkbox>
          </th>
          <th v-for="header in props.headers" :key="header.text">
            <v-icon small>arrow_upward</v-icon>
            {{ header.text }}
          </th>
        </tr>
      </template>
      <template v-slot:items="props">
        <tr :active="props.selected" @click="props.selected = !props.selected">
          <td>
            <v-checkbox :input-value="props.selected" primary hide-details></v-checkbox>
          </td>
          <td>{{ props.item.name }}</td>
          <td>{{ props.item.calories }}</td>
          <td>{{ props.item.fat }}</td>
        </tr>
      </template>
    </v-data-table>
    <v-btn @click="deleteRow">Delete Selected</v-btn>
  </div>
</template>

<script>
import { mapGetters, mapMutations } from "vuex";
export default {
  name: "HelloWorld",
  data(){
    return {
      selected: []
    }
  },
  watch: {
    selected: function(n, o){
      this.setSelected(n) //selected is watched, and when ever its changed store will be updated.
    }
  },
  computed: {
    ...mapGetters({
      getHeaders: "getHeaders",
      getDesserts: "getDesserts"
    })
  },
  methods: {
    ...mapMutations({
      setSelected: "setSelected", //Added a new method from mutation
      deleteRow: "deleteRow",

    }),
    toggleAll() {
      if (this.selected.length) this.selected = [];
      else this.selected = this.getDesserts.slice();
    }
  }
};
</script>



...