Update value in multidimensional array in Vue

冷暖自知 提交于 2020-01-02 08:36:38

问题


I understand from the caveats portion of the Vue docs that updating a value in an array in the following manner will not work:

  this.arr[idx] = newVal

and that one should use splice(). I am using a 2D array to store grid data, and I am having a difficult time updating the value when a cell in the grid is clicked.

Here is my template:

  <tr
      v-for="(row, rowKey, index) in grid"
        :key="rowKey">
        <th
          class="row-col-label"
        >{{rowKey+1}}</th>
        <td
            v-for="(col, colKey, index) in row"
            :key="colKey"
            @click="selectCell(rowKey, colKey)"
            :class="{'selected' : cellSelected(rowKey, colKey)}"
        >
        {{col}}
        </td>
      </tr>

And here is the relevant code for the Vue component:

 created () {
  this.initColHead()
  this.createSpreadSheet()
 },
 data () {
  return {
   selected: '',
   grid: [],
   colHead: [' '],
   isSelected: false
 }
},
methods: {
 initColHead () {
   this.colHead.push(...'ABC'.split(''))
 },
 createSpreadSheet () {
   for (let i = 0; i <= 2; i++) {
     this.grid[i] = []
      for (let j = 0; j <= 2; j++) {
       this.grid[i][j] = false
      }
   }
 },
selectCell (row, col) {
  this.isSelected = true
  console.log(`row ${row} col ${col}`)
  this.grid[row].splice(col, 1, true)
  for (let i = 0; i <= 2; i++) {
    for (let j = 0; j <= 2; j++) {
      console.log(this.grid[i][j])
    }
  }
},
cellSelected (row, col) {
  return (this.grid[row][col] === true)
}
}

So I am attempting to add a true value to the cell that is click at the given row col locations provided in the my selectCell method. However, the data in my grid is not updated to reflect the newly added value. How exactly do I update values in a multidimensional array in Vue?


回答1:


One method that works:

selectCell (row, col) {
  //make a copy of the row
  const newRow = this.grid[row].slice(0)
  // update the value
  newRow[col] = true
  // update it in the grid
  this.$set(this.grid, row, newRow)
},

Here is an example.

console.clear()


new Vue({
  el: "#app",
  created() {
    this.initColHead()
    this.createSpreadSheet()
  },
  data() {
    return {
      selected: '',
      grid: [],
      colHead: [' '],
      isSelected: false
    }
  },
  methods: {
    initColHead() {
      this.colHead.push(...'ABC'.split(''))
    },
    createSpreadSheet() {
      for (let i = 0; i <= 2; i++) {
        this.grid[i] = []
        for (let j = 0; j <= 2; j++) {
          this.grid[i][j] = false
        }
      }
    },
    selectCell(row, col) {
      const newRow = this.grid[row].slice(0)
      newRow[col] = true
      this.$set(this.grid, row, newRow)
    },
    cellSelected(row, col) {
      return (this.grid[row][col] === true)
    }
  }
})
.selected {
  background-color: green;
}
<script src="https://unpkg.com/vue@2.2.6/dist/vue.js"></script>
<div id="app">
  <table>
    <tr v-for="(row, rowKey, index) in grid" :key="rowKey">
      <th class="row-col-label">{{rowKey+1}}</th>
      <td v-for="(col, colKey, index) in row" :key="colKey" @click="selectCell(rowKey, colKey)" :class="{'selected' : cellSelected(rowKey, colKey)}">
        {{col}}
      </td>
    </tr>
  </table>
</div>

If I think of something better I'll update later.




回答2:


The difficulty is that you're building the array in a way that Vue does not make its rows reactive. You could build the array and then assign it to the data item as a whole so that Vue would make it reactive, or you can build the array (at last the rows) using push, which will make them reactive. Then you can modify individual elements using splice. Modifying Bert's example:

console.clear()


new Vue({
  el: "#app",
  created() {
    this.initColHead()
    this.createSpreadSheet()
  },
  data() {
    return {
      selected: '',
      grid: [],
      colHead: [' '],
      isSelected: false
    }
  },
  methods: {
    initColHead() {
      this.colHead.push(...'ABC'.split(''))
    },
    createSpreadSheet() {
      for (var i = 0; i <= 2; i++) {
        this.grid.push([]);
        for (var j = 0; j <= 2; j++) {
          this.grid[i].push(false);
        }
      }
    },
    selectCell(row, col) {
      this.grid[row].splice(col, 1, true);
    },
    cellSelected(row, col) {
      return (this.grid[row][col] === true)
    }
  }
})
.selected {
  background-color: green;
}
<script src="https://unpkg.com/vue@2.2.6/dist/vue.js"></script>
<div id="app">
  <table>
    <tr v-for="(row, rowKey, index) in grid" :key="rowKey">
      <th class="row-col-label">{{rowKey+1}}</th>
      <td v-for="(col, colKey, index) in row" :key="colKey" @click="selectCell(rowKey, colKey)" :class="{'selected' : cellSelected(rowKey, colKey)}">
        {{col}}
      </td>
    </tr>
  </table>
</div>


来源:https://stackoverflow.com/questions/45644781/update-value-in-multidimensional-array-in-vue

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!