Vuejs 2,VUEX,编辑数据时的数据绑定

时间:2017-01-25 21:37:15

标签: data-binding vue.js vuejs2 vue-router vuex

我有一个用户个人资料部分,我试图让用户编辑他们的信息。我正在使用vuex存储用户配置文件数据并将其拉入表单。编辑表单位于userProfile组件的子组件中 - 它加载数据保存将其提交给VUEX。

因此我可以使用VUEX中的数据填充表单,但是只要我更改表单中的任何值,它就会更改父组件中的值。

在保存表单之前,我没有对VUEX进行更改,因此这意味着数据绑定到VUEX的两个方向。我觉得这是不可能的。在这种情况下,不希望由于用户是否更改某些数据,然后导航而不实际点击“保存”,数据仍然是VUEX已更改。

注意,这是一个简化的例子。我实际上使用路由器视图加载子组件,或者我将通过道具传递数据。我已经测试过直接加载编辑配置文件组件,就像它在下面一样,我有同样的问题。

请参阅下面的代码,我找不到为什么数据被发送回商店。任何帮助是极大的赞赏。

在父级中,我设置检索用户数据,如下所示:

<template>
    <div class="content">
        <h1>{{getUserDetails.firstname}} {{getUserDetails.lastname}} </h1>
        <edit-profile></edit-profile>
    </div>
</template>
<script>
    import { mapGetters } from 'vuex';
    import EditProfile from './Edit.vue';

    export default {
        data() {
            return {
                // data
            }
        },
        created () {
            this.fetchData();
        },
        components: {
            EditProfile:EditProfile
        },
        computed: mapGetters([
            'getUserDetails'
        ]),
        methods: {
            fetchData: function () {
                var _this = this;
                // ajax call - then
                _this.$store.commit('setData', {
                    name: 'userDetails',
                    data: response.data.data.userDetails
                });
            }
        }
    }
</script>

这会加载结果并将其存储在商店中,效果很好。

我的商店有这个:

const store = new Vuex.Store({
    state: {
        userDetails: {}
    },
    mutations: {
        setData(state, payload){
            state[payload.name] = payload.data;
        }
    },
    getters: {
        getUserDetails: state => {
            return state.userDetails;
        }
    }
}

这里的一切都在发挥作用。

在我的带有编辑表单的子组件中,我填充了这样的表单:

<template>
    <form>
        <label>Name</label>
        <input name="firstname" v-model="profile.firstname">
        <input name="lastname" v-model="profile.lastname">
        <button v-on:click="save">submit</button>
     </form>
</template>

<script>
import {mapGetters } from 'vuex';

export default {
    data() {
        return {
            profile:{}
        }
    },
    watch: {
        getUserDetails (newData){
            this.profile = newData;
        }
    },
    created (){
        this.profile = this.$store.getters.getUserDetails;
    },
    computed: mapGetters([
        'getUserDetails'
    ]),
    methods:{
        save (){
            var _this = this;
            // ajax call to POST this.profile then
            _this.$store.commit('setData', {
                name: 'userDetails',
                data: this.profile
            });
        }
    }
}
</script>

4 个答案:

答案 0 :(得分:8)

如果您正在寻找带有vuex的非绑定解决方案,您可以克隆该对象并使用v-model的本地版本而不是提交提交它。

在您创建的生命周期函数中

执行此操作:

created (){
    this.profile = Object.assign({}, this.$store.getters.getUserDetails);
},

答案 1 :(得分:1)

为什么我认为它没有按预期工作:您正在接收一个对象,将其绑定到本地属性。然后,当您更改该本地属性时,它会被对象指针(/内存地址)绑定到商店的对象。 根据状态的用户配置文件对象的属性创建一个新对象并在该新对象上设置属性应该可以解决问题,因为新对象在内存中拥有自己的地址,会指向另一个地方...

插图:

created (){
    // create a new object with {...}
    this.profile = {
        // assign values to properties of same name
        firstName: this.$store.getters.getUserDetails.firstName,
        lastName: this.$store.getters.getUserDetails.lastName,
    };
},

然而如果这些属性(firstName,lastName)是对象或数组(通过指向内存地址的指针访问的任何内容),那么这也不起作用。

所以...在这种情况下我最有可能最终做的就是这样:

data() {
    return {
        firstName: '',
        lastName: ''
    }
},

这定义了本地属性。加载数据时,您将使用Vuex商店中的配置文件数据填充本地值。

created() {
    let profile = this.$store.getters.getUserDetails;
    if (profile.firstName && profile.lastName) {
        this.firstName = profile.firstName;
        this.lastName = profile.lastName;
    }
},

然后,在保存时,使用局部变量更新商店的值。

methods: {
    save() {
        let profile = {
            firstName: this.firstName,
            lastName: this.lastName
        };

        // ajax call to POST this.profile then
        this.$store.commit('setData', {
            name: 'userDetails',
            data: profile
        });
    }
}

我是从头顶写的,所以这里可能有一个错误或错字......但我希望至少我的逻辑是正确的;-P并且对你很清楚。

专业:在您准备好保存已修改的信息之前,您不会在其他地方反映出来。

Con :如果您需要反映临时更改(可能在用户个人资料预览区域中),这可能会也可能不会起作用,具体取决于您的应用的结构。在这种情况下,你可能想将@input绑定或保存到state.temporaryUserProfile对象?

我还是Vue.js的新手,2周前开始使用它。希望这是明确和正确的:))

答案 2 :(得分:1)

问题是由使用带有mapGetters的v-model引起的 - 这会创建您所描述的双向绑定。简单的解决方案是使用值代替:

:value="profile.firstName"

这样,表单只会更改字段的本地副本,而不会将更改推回到Vuex存储区。

答案 3 :(得分:0)

@Afik​​Deri解决方案很棒,但是它只能创建一个浅表副本(例如,如果您有嵌套的对象(通常很常见),它将无法正常工作),要解决此问题,您可以序列化然后< em> parse 您的 vuex 状态对象getUserDetails,如下所示:

created (){
    this.profile = JSON.parse(JSON.stringify(this.$store.getters.getUserDetails));
}