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
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>
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.