@HenLeiko

Почему нет двусторонний привязки v-model?

Делал todo лист, а именно возможность редактирования задачи с использованием popup окна. Решил сделать копию с состоянием vuex путём парсинга в другую переменную. Но после привязки через v-model данный объект просто не обновляется.
Если написать что-то в поле, а после сменить фокус, то значение поля опять меняется на свойство объект.
В чём может быть причина?
UpdateTask.vue

<template lang="">
  <q-card class="card" style="min-width: 350px">
    <q-card-section>
      <div class="text-h6">Добавить задачу</div>
    </q-card-section>
    <form @submit.prevent="submitForm">
      <q-card-section class="q-pt-none">
        <q-input v-model="test.title" label="Заголовок" :rules="[val => !!val || 'Field is required']"
          @keyup.enter="prompt = false" />
      </q-card-section>

      <q-card-section class="q-pt-none">
        <q-input v-model="test.desc" value="qwe" label="Описание" :rules="[val => !!val || 'Field is required']"
          @keyup.enter="prompt = false" />
      </q-card-section>
      {{test}}
      <q-card-section>
        <q-input label="Дата" v-model="test.date">
          <template v-slot:append>
            <q-icon name="event" />
            <q-popup-proxy ref="qDateProxy" transition-show="scale" transition-hide="scale">
              <q-date v-model="test.date" @input="() => $refs.qDateProxy.hide()" mask="DD/MM/YYYY"></q-date>
            </q-popup-proxy>
          </template>
        </q-input>
        <q-card-section>
          {{test.title}}
          <q-select class="qwe" v-model="test.users" :options="users" label="Исполнители" option-label="firstName"
            clearable multiple options-selected-class="text-deep-orange">
            <template v-slot:option="scope">
              <q-item v-bind="scope.itemProps" v-on="scope.itemEvents">
                <q-item-section>
                  <q-item-label v-html="scope.opt.firstName"></q-item-label>
                  <q-item-label caption>{{ scope.opt.lastName }}</q-item-label>
                </q-item-section>
                <q-item-section avatar>
                  <q-avatar>
                    <img :src="scope.opt.avatar">

                  </q-avatar>
                </q-item-section>
              </q-item>
            </template>
          </q-select>
        </q-card-section>
      </q-card-section>
      <q-card-actions align="right" class="text-primary">
        <q-btn flat label="Отмена" v-close-popup />
        <q-btn flat type="submit" label="Добавить задачу" />
        {{test.users}}
      </q-card-actions>
    </form>
  </q-card>
</template>
<script>
import { computed, ref } from '@vue/runtime-core';
import { useStore, mapGetters } from "vuex";

  export default {
    props: ['post', 'id'],
    setup(props) {
      const store = useStore()

      const getUsers = computed(() => {
        return store.getters.getUsers
      })

    //   const test = computed({
    //     get: () => store.state.posts.posts[props.id],
    //     set: test => {
    //       store.dispatch('posts/updateTask', test)
    //     }
    //  })

    let test = JSON.parse ( JSON.stringify ( props.post ) )



    function submitForm () {
          store.dispatch('posts/updateTask', {
            id: props.id,
            updates: test
          })
        }

      return {
        users: computed(() => store.state.posts.users),
        test,
        submitForm
      }
    }
  }

</script>
<style>
.qwe {
  width: 100%;
}
</style>


TodoCard.vue

<template lang="">
  <q-card flat bordered class="my-card bg-grey-1">
    <q-card-section>
      <div class="row items-center no-wrap">
        <div class="col">
          <div class="text-h6">{{post.title}}</div>
          <div class="text-subtitle2">
            <q-chip v-for="user in post.users">
              <q-avatar>
                <img :src="user.avatar">
              </q-avatar>
              {{user.firstName}}
            </q-chip>
          </div>
        </div>
        <div class="col-auto">
          <q-btn color="grey-7" round flat icon="more_vert">
            <q-menu cover auto-close>
              <q-list>
                <q-item clickable>
                  <q-item-section>Remove Card</q-item-section>
                </q-item>
                <q-item clickable>
                  <q-item-section>Send Feedback</q-item-section>
                </q-item>
                <q-item clickable>
                  <q-item-section>Share</q-item-section>
                </q-item>
              </q-list>
            </q-menu>
          </q-btn>
        </div>
      </div>
    </q-card-section>
    <q-card-section>
      {{post.desc}}
    </q-card-section>
    <q-card-section>

    </q-card-section>

    <q-separator></q-separator>

    <q-card-actions>
      <q-btn @click="deleteTask()" flat>Удалить</q-btn>
      <q-btn @click="ez = true" flat>Редактировать</q-btn>
      <q-dialog v-model="ez" persistent>
        <apdates :post="post" :id="id"></apdates>
      </q-dialog>
    </q-card-actions>
  </q-card>


</template>
<script>
import { computed, ref } from '@vue/runtime-core'
import { useStore } from "vuex"
import { mapActions } from "vuex"
import apdates from 'components/UpdateTask.vue'



  export default {
    props: ['post', 'id'],
    components: {
      apdates,

    },
    setup(props) {
        const store = useStore()

        function deleteTask () {
          store.dispatch('posts/deleteTask', props.id)
        }

        return {
          deleteTask,
          ez: ref(false),
        }
      }


    }



</script>
<style lang="scss">
  .my-card {
    //  align-self: center;
    display: block;
  }

</style>


post-store.js

import { uid } from 'quasar'

const state = {
  posts: {
    'ID0': {
      id: 1,
      title: 'Some title one',
      desc: 'Some desc one',
      users: [
        {
          firstName: 'Den',
          lastName: 'Den',
          avatar: 'https://cdn.quasar.dev/img/boy-avatar.png'
        }
      ]
      // author: 'Den',

    },
    'ID2': {
      id: 2,
      title: 'Some title two',
      desc: 'Some desc two',
      users: [
        {
          firstName: 'Den',
          lastName: 'Den',
          avatar: 'https://krot.info/uploads/posts/2021-02/1613819225_43-p-kruglii-fon-dlya-avi-43.png'
        }
      ],
    },
    'ID3': {
      id: 3,
      title: 'Some title three',
      desc: 'Some desc three',
      users: [
        {
          firstName: 'Den',
          lastName: 'Den',
          avatar: 'https://i.pinimg.com/originals/20/3a/7a/203a7a27dc41ffca2bfbd077d8409bd4.jpg'
        }
      ]
    }
  },
  users: [
    {
      id: 1,
      firstName: 'Nigger',
      lastName: 'niggos',
      avatar: 'https://pixelbox.ru/wp-content/uploads/2021/02/youtube-avatar-anime-95.jpg'
    },
    {
      id: 2,
      firstName: 'Vasya',
      lastName: 'Pupkin',
      avatar: 'https://cdn.quasar.dev/img/boy-avatar.png'
    },
    {
      id: 3,
      firstName: 'Nasyua',
      lastName: 'Kuznicova',
      avatar: 'https://i.pinimg.com/originals/20/3a/7a/203a7a27dc41ffca2bfbd077d8409bd4.jpg'
    },
  ]
}

const mutations = {
  addTask (state, payload) {
    state.posts[payload.id] = payload.task
  },
  deleteTask (state, key) {
    delete state.posts[key]
  },
  updateTask (state, payload) {
    Object.assign(state.posts[payload.id], payload.updates)
  }
}

const actions = {
  addTask ({commit}, task) {
    let id = uid()
    let payload = {
      id: id,
      task: task
    }
    commit('addTask', payload)
  },
  deleteTask ({commit}, key) {
    commit('deleteTask', key)
  },
  updateTask ({commit}, payload) {
    commit('updateTask', payload)
    console.log(payload);
  }
}

const getters = {
  getUsers (state) {
    return state.users
  }
}

export default {
  namespaced: true,
  state,
  mutations,
  actions,
  getters
}

Видео с демонстрацией проблемы
  • Вопрос задан
  • 96 просмотров
Решения вопроса 1
0xD34F
@0xD34F Куратор тега Vue.js
Потому что объект не реактивный. Надо в reactive завернуть.
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы