I'm a beginner programmer and I create a spa like trello. Creates boards. In the board creates lists, they are displayed different with different id, but the list items are displayed with the same id and they are duplicated in each list. Sorry for my english:) Help me, please and tell in detail what the problem is.. Thank you very much
vuex file router.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
boards: JSON.parse(localStorage.getItem('boards') || '[]'),
lists: [],
items: []
// items: JSON.parse(localStorage.getItem('items') || '[]')
// lists: JSON.parse(localStorage.getItem('lists') || '[]')
},
mutations: {
addBoard(state, board) {
state.boards.push(board)
localStorage.setItem('boards', JSON.stringify(state.boards))
},
addList(state, list) {
state.lists.push(list)
// localStorage.setItem('lists', JSON.stringify(state.lists))
},
createItemListt(state, item) {
state.items.push(item)
// localStorage.setItem('items', JSON.stringify(state.items))
}
},
actions: {
addBoard({commit}, board) {
commit('addBoard', board)
},
addList({commit}, list) {
commit('addList', list)
},
createItemListt({commit}, item) {
commit('createItemListt', item)
}
},
getters: {
boards: s => s.boards,
taskById: s => id => s.boards.find(t => t.id === id),
lists: d => d.lists,
items: a => a.items
},
modules: {
}
})
the page on which the lists are created MyBoard.vue
<template>
<div>
<div class="wrapper">
<div class="row">
<h1>{{board.title}}</h1>
<div class="list " v-for="list in lists" :key="list.idList">
<div class="list__title">
<h3>{{list.titleList}}</h3>
</div>
<div class="list__card" v-for="item in items" :key="item.idItemList">
<span class="list__item">{{item.itemList}}</span>
<a class="btn-floating btn-tiny btn-check" tag="button">
<i class="material-icons">check</i>
</a>
</div>
<createItemList />
</div>
<createList />
</div>
</div>
</div>
</template>
<script>
export default {
computed: {
board() {
return this.$store.getters.taskById(+this.$route.params.id);
},
lists() {
return this.$store.getters.lists;
},
items() {
return this.$store.getters.items;
}
},
components: {
createList: () => import("../components/createList"),
createItemList: () => import("../components/createItemList")
}
};
</script>
CreateList.Vue
<template>
<div>
<div class="row">
<div class="new-list" v-show="isCreating">
<div class="list__title input-field">
<input
type="text"
required
id="list-title"
class="none validate"
tag="button"
autofocus
v-model="titleList"
v-on:keyup.enter="createList"
/>
<label for="list-title">Enter Title List</label>
</div>
<a class="btn-floating transparent btn-close" tag="button" @click="closeList">
<i class="material-icons">close</i>
</a>
</div>
<div class="create-list z-depth-2" v-show="!isCreating">
<p>Create list</p>
<a
class="btn-floating btn-large waves-effect waves-light deep-purple lighten-2 pulse"
tag="button"
@click="addList"
v-on:keyup.enter="addList"
>
<i class="material-icons">add</i>
</a>
</div>
</div>
</div>
</template>
<script>
export default {
data: () => ({
isCreating: false,
titleList: "",
idList: ""
}),
methods: {
addList() {
this.isCreating = true;
},
closeList() {
this.isCreating = false;
},
createList() {
if (this.titleList == "") {
return false;
}
const list = {
idList: Date.now(),
titleList: this.titleList
};
this.$store.dispatch("addList", list);
this.titleList = "";
this.isCreating = false;
console.log(list.titleList);
}
}
};
</script>
CreateItemList.vue
<template>
<div>
<div class="add-item">
<div class="textarea-item input-field" v-show="isAdding">
<input
type="text"
class="validate"
id="list-item"
v-model="itemList"
v-on:keyup.enter="createItemList"
autofocus
/>
<label for="list-item">Enter Item List</label>
</div>
<a class="waves-effect waves-light btn" v-show="!isAdding" @click="addCard">
<i class="material-icons right">add</i>Add Card
</a>
</div>
</div>
</template>
<script>
export default {
data: () => ({
isAdding: false,
itemList: "",
}),
methods: {
addCard() {
this.isAdding = true;
},
createItemList() {
if (this.itemList == "") {
return false;
}
const item = {
idItemList: Date.now(),
itemList: this.itemList
};
this.$store.dispatch("createItemListt", item);
this.itemList = "";
this.isAdding = false;
}
}
};
</script>
Tried to go with the basic idea of the structure you laid out. I added:
id
to all items, so they can be identifedchildren
to appropriate items, so you can keep track of what's in them const store = new Vuex.Store({ state: { tables: [ { id: 1, children: ['1.1', '1.2'] }, { id: 2, children: ['2.1'] } ], lists: [ { id: '1.1', children: ['1.1.1'] }, { id: '1.2', children: ['1.2.1'] }, { id: '2.1', children: ['2.1.1', '2.1.2'] }, ], cards: [ { id: '1.1.1' }, { id: '1.2.1' }, { id: '2.1.1' }, { id: '2.1.2' }, ] }, mutations: { ADD_CARD(state, listId) { const list = state.lists.find(e => e.id === listId) const cards = state.cards const card = { id: Date.now() } cards.push( card ) list.children.push( card.id ) }, ADD_LIST(state, tableId) { const table = state.tables.find(e => e.id === tableId) const lists = state.lists const list = { id: Date.now(), children: [] } lists.push( list ) table.children.push( list.id ) }, ADD_TABLE(state) { const tables = state.tables const table = { id: Date.now(), children: [] } tables.push( table ) }, TRY_MOVING_LIST(state) { const table1 = state.tables.find(e => e.id === 1) const table2 = state.tables.find(e => e.id === 2) const item = table1.children.pop() // remove the last item table2.children.push(item) } }, actions: { addCard({ commit }, listId) { commit('ADD_CARD', listId) }, addList({ commit }, tableId) { commit('ADD_LIST', tableId) }, addTable({ commit }) { commit('ADD_TABLE') }, tryMovingList({ commit }) { commit('TRY_MOVING_LIST') } }, getters: { getTables: s => s.tables, getListById: s => id => s.lists.find(e => e.id === id), getCardById: s => id => s.cards.find(e => e.id === id), } }) Vue.component('CustomCard', { props: ['card'], template: `<div> card ID: {{ card.id }}<br /> </div>` }) Vue.component('CustomList', { props: ['list'], template: `<div> list ID: {{ list.id }}<br /> <custom-card v-for="item in list.children":key="item":card="getCard(item)" /> <button @click="addCard">ADD CARD +</button> <hr /> </div>`, methods: { getCard(id) { return this.$store.getters.getCardById(id) }, addCard() { this.$store.dispatch('addCard', this.list.id) } } }) Vue.component('CustomTable', { props: ['cTable'], template: `<div> table ID: {{ cTable.id }}<br /> <custom-list v-for="item in cTable.children":key="item":list="getList(item)" /> <button @click="addList">ADD LIST +</button> <hr /> </div>`, methods: { getList(id) { return this.$store.getters.getListById(id) }, addList(id) { this.$store.dispatch('addList', this.cTable.id) } } }) new Vue({ el: "#app", store, computed: { tables() { return this.$store.state.tables } }, methods: { addTable() { this.$store.dispatch('addTable') }, tryMovingList() { // this function will move the last list in table ID 1 // to the end of table ID 2's lists // NOT FOOLPROOF - you should add error handling logic. this.$store.dispatch('tryMovingList') } } })
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script> <script src="https://unpkg.com/vuex"></script> <div id="app"> <button @click="tryMovingList()">MOVE LIST</button><br /> <button @click="addTable()">ADD TABLE +</button> <hr /> <custom-table v-for="item in tables":key="'table-' + item.id":c-table="item" /> </div>
With this setup you can change the hierarchy quite easily: just delete an ID from one Array
of children and add it to another (eg remove '1.1'
from table
ID 1's children
array and add it to table
ID 2's children
array - everything moved to table
ID 2. tryMovingList()
does exactly this - this method/action is not foolproof , just for you to try out moving a whole list)
There could be other patterns to solve this problem (like a real linked list data structure or the mediator pattern), but for smaller apps this is OK, I think (I would use it... :) ).
If you want to store state in localStorage
on mutations, don't do it by yourself - use Vuex 's integrated subscribe
mechanism: https://vuex.vuejs.org/api/#subscribe
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.