Sortable list.

This commit is contained in:
aminecmi 2022-01-29 13:51:57 +01:00
parent f99deb2631
commit a62285ee06
5 changed files with 100 additions and 23 deletions

13
package-lock.json generated
View File

@ -13256,6 +13256,11 @@
}
}
},
"sortablejs": {
"version": "1.14.0",
"resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.14.0.tgz",
"integrity": "sha512-pBXvQCs5/33fdN1/39pPL0NZF20LeRbLQ5jtnheIPN9JQAaufGjKdWduZn4U7wCtVuzKhmRkI0DFYHYRbB2H1w=="
},
"source-list-map": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz",
@ -14719,6 +14724,14 @@
"integrity": "sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw==",
"dev": true
},
"vuedraggable": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/vuedraggable/-/vuedraggable-4.1.0.tgz",
"integrity": "sha512-FU5HCWBmsf20GpP3eudURW3WdWTKIbEIQxh9/8GE806hydR9qZqRRxRE3RjqX7PkuLuMQG/A7n3cfj9rCEchww==",
"requires": {
"sortablejs": "1.14.0"
}
},
"watchpack": {
"version": "1.7.5",
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.7.5.tgz",

View File

@ -12,7 +12,8 @@
"core-js": "^3.6.5",
"vue": "^3.0.0",
"vue-class-component": "^8.0.0-0",
"vue-router": "^4.0.0-0"
"vue-router": "^4.0.0-0",
"vuedraggable": "^4.1.0"
},
"devDependencies": {
"@typescript-eslint/eslint-plugin": "^4.18.0",

View File

@ -0,0 +1,48 @@
<template>
<div class="panel-block" v-bind:class="{'disabled': element.loading}">
<span class="icon is-pulled-left" v-if="canMove">
<ion-icon name="move-outline"></ion-icon>
</span>
<input type="checkbox" v-model="element.checked" v-on:change="updateItem(element)">
<div class="field is-horizontal has-addons">
<div class="control">
<input class="input" type="text" v-bind:disabled="element.checked" v-model="element.content"
v-on:blur="updateItem(element)">
</div>
<div class="control" v-if="!element.checked">
<a class="button is-primary" v-on:click="updateItem(element)">
Save
</a>
</div>
</div>
</div>
</template>
<script>
export default {
name: "ListItem",
props: ['item', 'canMove'],
data: function () {
return {
element: this.item
}
},
methods: {
updateItem: function () {
this.$emit('updateItem', this.element)
}
}
}
</script>
<style scoped>
.panel-block.disabled {
opacity: .5;
}
.field, .field .control:first-child {
width: 100%;
}
</style>

View File

@ -1,5 +1,5 @@
<template>
<div>
<div class="block">
<ItemCreateModal v-if="addModalShown" v-bind:add-modal-shown="addModalShown" v-bind:list-id="listId"
v-on:newItem="addItem" v-on:toggleModalItem="toggleModal"></ItemCreateModal>
<div class="panel is-info" v-if="!loading">
@ -27,28 +27,31 @@
</div>
</div>
<div class="panel-block" v-for="item in items" :key="item.id" v-bind:class="{'disabled': item.loading}">
<input type="checkbox" v-model="item.checked" v-on:change="updateItem(item)">
<div class="field is-horizontal has-addons">
<div class="control">
<input class="input" type="text" v-bind:disabled="item.checked" v-model="item.content" v-on:blur="updateItem(item)">
</div>
<div class="control" v-if="!item.checked">
<a class="button is-primary" v-on:click="updateItem(item)">
Save
</a>
</div>
</div>
<draggable
v-model="items"
group="people"
@change="onChange"
item-key="id" v-if="searchQ.length <= 0">
<template #item="{element}">
<ListItem v-bind:item="element" v-bind:can-move="true" v-on:updateItem="updateItem"></ListItem>
</template>
</draggable>
<div v-if="searchQ.length > 0">
<ListItem v-for="element in items" v-bind:can-move="false" :key="element.id" v-bind:item="element" v-on:updateItem="updateItem"></ListItem>
</div>
</div>
</div>
</template>
<script>
import ItemCreateModal from "@/components/ItemCreateModal";
import draggable from 'vuedraggable'
import ListItem from "@/components/ListItem";
export default {
name: "List",
components: {ItemCreateModal},
components: {ListItem, ItemCreateModal, draggable},
data: function () {
return {
listId: this.$route.params.id,
@ -57,12 +60,15 @@ export default {
items: [],
initialItems: [],
loading: true,
addModalShown: false
addModalShown: false,
drag: false
}
},
methods: {
fetchListAndItems: function () {
this.loading = true;
fetchListAndItems: function (ignoreLoading) {
if (!ignoreLoading) {
this.loading = true;
}
fetch('http://localhost:7000/api/lists/' + this.listId + '/items', {
method: 'GET',
headers: {
@ -79,7 +85,7 @@ export default {
this.loading = false;
})
},
updateItem: function (item) {
updateItem: function (item, reloadAll) {
item.loading = true;
const itemCopy = Object.assign({}, item);
delete itemCopy.loading;
@ -91,6 +97,9 @@ export default {
},
body: JSON.stringify(itemCopy)
}).finally(() => {
if (reloadAll) {
this.fetchListAndItems(true);
}
item.loading = false;
})
},
@ -111,6 +120,14 @@ export default {
addItem: function (item) {
this.initialItems.push(item);
this.recopyItemsObject();
},
onChange: function (event) {
if (event.moved) {
console.log(event.moved.newIndex)
const i = this.initialItems.find(i => i.id === event.moved.element.id)
i.position = event.moved.newIndex
this.updateItem(i, true);
}
}
},
beforeMount() {
@ -120,9 +137,7 @@ export default {
</script>
<style scoped>
.panel-block.disabled {
opacity: .5;
}
.field, .field .control:first-child {
width: 100%;
}

View File

@ -1,5 +1,5 @@
<template>
<div>
<div class="block">
<ListCreateUpdateModal v-if="addModalShown" v-bind:add-modal-shown="addModalShown" v-on:newList="addListItem"
v-on:updatedItem="updateListItem"
v-on:toggleModal="toggleModal" v-bind:item="selectedItem"></ListCreateUpdateModal>