Reputation: 123
I'm having the following issue:
I want in the frondend to get a list of items based on the key 'order':
<div id="app">
<ul>
<li v-for="item in sorted">
{{item.order}} {{item.title}}
<button @click="changeOrderDown(item)">down</button>
<button @click="changeOrderUp(item)">up</button>
</li>
</ul>
</div>
based on the JSON you see below. When you click the button I want to swap out for example order 1 -> 2 and then 2 becomes 1
items: [
{
title: "test",
order: 1
},
{
title: "test2",
order: 2
},
{
title: "test3",
order: 3
}
]
I keep getting a duplicate key error cause i first change the first key and then the second. i resolved it to update the whole object at ones. that seems to work but still it doesn't behave the correct way.
computed: {
sorted() {
function compare(a, b) {
let comparison = 0;
if (a.order > b.order) {
comparison = 1;
} else if (a.order < b.order) {
comparison = -1;
}
return comparison;
}
return this.items.sort(compare)
},
},
methods: {
changeOrderDown(currentItem) {
let temp = this.items
let old_value = parseFloat(currentItem.order)
let new_value = parseFloat(currentItem.order) + 1;
console.log(old_value, new_value)
temp.filter(o => o.order === old_value)[0].order = new_value;
temp.filter(o => o.order === new_value)[0].order = old_value;
this.items = temp;
},
changeOrderUp(currentItem) {
let temp = this.items
let old_value = parseFloat(currentItem.order)
let new_value = parseFloat(currentItem.order) - 1;
console.log(old_value, new_value)
temp.filter(o => o.order === old_value)[0].order = new_value;
temp.filter(o => o.order === new_value)[0].order = old_value;
this.items = temp;
},
}
I made a codepen down below with the code from above. this is kinda a working example but it doesn't feel right. Can someone give me a push in the right direction?
https://codepen.io/frank-derks/pen/BaQVOZV
Upvotes: 0
Views: 1145
Reputation: 136
This solution is similar to Tim's, but a bit simpler and easier to follow:
<template>
<v-app>
<ul>
<li v-for="(item, index) in items" :key="index">
{{item.order}} {{item.title}} {{index}}
<button @click="changeOrderDown(item, index)" v-if="index != items.length-1">down</button>
<button @click="changeOrderUp(item, index)" v-if="index != 0">up</button>
</li>
</ul>
</v-app>
</template>
<script>
export default {
name: 'App',
data: () => ({
items: [
{
title: "test1",
order: 1
},
{
title: "test2",
order: 2
},
{
title: "test3",
order: 3
}
]
}),
methods: {
changeOrderDown(item, index) {
// save clicked item in temporary variable
let temp = item
// move the following item to the clicked element
this.items[index] = this.items[index + 1]
// move clicked item to destination
this.items[index + 1] = temp
},
changeOrderUp(item, index) {
// save clicked item in temporary variable
let temp = item
// move the following item to the clicked element
this.items[index] = this.items[index - 1]
// move clicked item to destination
this.items[index - 1] = temp
},
}
};
</script>
<template>
<v-app>
<ul>
<li v-for="(item, index) in items" :key="index">
{{item.order}} {{item.title}} {{index}}
<button @click="changeOrderDown(item, index)" v-if="index != items.length-1">down</button>
<button @click="changeOrderUp(item, index)" v-if="index != 0">up</button>
</li>
</ul>
</v-app>
</template>
<script>
export default {
name: 'App',
data: () => ({
items: [
{
title: "test1",
order: 1
},
{
title: "test2",
order: 2
},
{
title: "test3",
order: 3
}
]
}),
methods: {
changeOrderDown(item, index) {
// save clicked item in temporary variable
let temp = item
// move the following item to the clicked element
this.items[index] = this.items[index + 1]
// move clicked item to destination
this.items[index + 1] = temp
},
changeOrderUp(item, index) {
// save clicked item in temporary variable
let temp = item
// move the following item to the clicked element
this.items[index] = this.items[index - 1]
// move clicked item to destination
this.items[index - 1] = temp
},
}
};
</script>
Upvotes: 1
Reputation: 1229
Interesting challenge. Using my Vue 2 CLI sandbox app, I came up with functionality that doesn't require an 'order' property. Here is the component code:
<template>
<div class="swap-array-objects">
<h3>SwapArrayObjects.vue</h3>
<div class="row">
<div class="col-md-6">
<table class="table table-bordered">
<thead>
<tr>
<th>TITLE</th>
<th> </th>
<th> </th>
</tr>
</thead>
<tbody>
<tr v-for="(item, index) in items" :key="index">
<td>{{ item.title }}</td>
<td>
<button class="btn btn-secondary btn-sm" @click="moveUp(index)">Up</button>
</td>
<td>
<button class="btn btn-secondary btn-sm" @click="moveDown(index)">Down</button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
items: [
{
title: 'title1'
},
{
title: 'title2'
},
{
title: 'title3'
},
{
title: 'title4'
},
{
title: 'title5'
}
]
}
},
methods: {
moveUp(index) {
if (index === 0) {
return;
}
let priorIndex = index - 1;
let itemCopy = {...this.items[index]};
let priorItemCopy = {...this.items[priorIndex]};
// Swap array position with prior element
this.$set(this.items, priorIndex, itemCopy);
this.$set(this.items, index, priorItemCopy);
},
moveDown(index) {
if (index === this.items.length - 1) {
return;
}
let subsequentIndex = index + 1;
let itemCopy = {...this.items[index]};
let subsequentItemCopy = {...this.items[subsequentIndex]};
// Swap array positions with subsequent element
this.$set(this.items, subsequentIndex, itemCopy);
this.$set(this.items, index, subsequentItemCopy);
}
}
}
</script>
Upvotes: 2