admin管理员组

文章数量:1278883

I'm working on an application using vuejs with vuex which uses projects, with each project having one or more jobs.

I can add, delete and update the jobs. The adding and deleting is working perfect, but the updating is not.

The state in the vuex dev tools:

My HTML:

<div class="job-pact row" v-for="(job, index) in project.jobs">
        <div class="col-md-6">
            <div class="form-group" :class="{'has-error' : errors.has('jobs.' + index + '.function')}">
                <input type="text" name="jobs[function][]" class="form-control" v-model="job.function" @change="updateJobValue(index, 'function', $event.target.value)"/>
            </div>
        </div>
        <div class="col-md-4">
            <div class="form-group" :class="{'has-error' : errors.has('jobs.' + index + '.profiles')}">
                <input type="number" name="jobs[profiles][]" class="form-control" v-model="job.profiles" @change="updateJobValue(index, 'profiles', $event.target.value)"/>
            </div>
        </div>
        <div class="col-md-2">
            <button v-if="index == 0" class="btn btn-success btn-sm" @click="addJob"><i class="fa fa-plus"></i></button>
            <button v-if="index > 0" class="btn btn-danger btn-sm" @click="deleteJob(index);"><i class="fa fa-minus"></i></button>
        </div>
    </div>

As you can see, I have a v-for that is showing all my jobs. When editing a value inside my jobs, I use the @change event to update my value. And, at the bottom, I have two buttons to add and remove a job row.

My stores are divided into modules. The main store looks like this:

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex);

const state = {};

const getters = {};

const mutations = {};

const actions = {};

//Separate Module States
import jobCreator from './modules/job-creator/store';

export default new Vuex.Store({
    modules: {
        jobCreator: jobCreator
    },
    state,
    actions,
    mutations,
    getters
});

The module store for this specific problem:

import store from './../../store'

const state = {
    project: {
        title: null,
        description: null,
        jobs: []
    },
    defaultJob: {
        function: '',
        title: '',
        description: '',
        profiles: 1,
        location_id: '',
        category_id: '',
        budget: '',
    },
};

const getters = {}

const mutations = {

    addJob(state, job) {
        state.project.jobs.push(job);
    },
    deleteJob(state, index) {
        state.project.jobs.splice(index, 1);
    },
    updateJobValue(state, params) {
        Object.assign(state.project.jobs[params.jobIndex], {
            [params.field]: params.value
        });
    }
};

const actions = {
    addJob: function (context) {
        contextmit('addJob', state.defaultJob);
    },
    deleteJob: function (context, index) {
        contextmit('deleteJob', index);
    },
    updateJobValue: function (context, params) {
        contextmit('updateJobValue', params);
    },
};

const module = {
    state,
    getters,
    mutations,
    actions
};

export default module;

The project state is mapped to a puted property of my vue instance:

puted: {
       ...mapState({
           project: state => state.jobCreator.project,
       }),
}

The problem is the following: In the image of the application, you can see that I entered "vin" in one of the fields, but all of the fields are updating.

So, all of the function fields of all the jobs have been updated to my last entry, instead of only the one I want.

What am I doing wrong?

PS:

I also tried the following in my mutation function:

updateJobValue(state, params) {
    var job = state.project.jobs[params.jobIndex];
    job[params.field] = params.value;

    Vue.set(state.project.jobs, params.jobIndex, job);
}

But it's giving me the same result.

UPDATE: As requested, I created a jsFiddle to show my problem

I'm working on an application using vuejs with vuex which uses projects, with each project having one or more jobs.

I can add, delete and update the jobs. The adding and deleting is working perfect, but the updating is not.

The state in the vuex dev tools:

My HTML:

<div class="job-pact row" v-for="(job, index) in project.jobs">
        <div class="col-md-6">
            <div class="form-group" :class="{'has-error' : errors.has('jobs.' + index + '.function')}">
                <input type="text" name="jobs[function][]" class="form-control" v-model="job.function" @change="updateJobValue(index, 'function', $event.target.value)"/>
            </div>
        </div>
        <div class="col-md-4">
            <div class="form-group" :class="{'has-error' : errors.has('jobs.' + index + '.profiles')}">
                <input type="number" name="jobs[profiles][]" class="form-control" v-model="job.profiles" @change="updateJobValue(index, 'profiles', $event.target.value)"/>
            </div>
        </div>
        <div class="col-md-2">
            <button v-if="index == 0" class="btn btn-success btn-sm" @click="addJob"><i class="fa fa-plus"></i></button>
            <button v-if="index > 0" class="btn btn-danger btn-sm" @click="deleteJob(index);"><i class="fa fa-minus"></i></button>
        </div>
    </div>

As you can see, I have a v-for that is showing all my jobs. When editing a value inside my jobs, I use the @change event to update my value. And, at the bottom, I have two buttons to add and remove a job row.

My stores are divided into modules. The main store looks like this:

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex);

const state = {};

const getters = {};

const mutations = {};

const actions = {};

//Separate Module States
import jobCreator from './modules/job-creator/store';

export default new Vuex.Store({
    modules: {
        jobCreator: jobCreator
    },
    state,
    actions,
    mutations,
    getters
});

The module store for this specific problem:

import store from './../../store'

const state = {
    project: {
        title: null,
        description: null,
        jobs: []
    },
    defaultJob: {
        function: '',
        title: '',
        description: '',
        profiles: 1,
        location_id: '',
        category_id: '',
        budget: '',
    },
};

const getters = {}

const mutations = {

    addJob(state, job) {
        state.project.jobs.push(job);
    },
    deleteJob(state, index) {
        state.project.jobs.splice(index, 1);
    },
    updateJobValue(state, params) {
        Object.assign(state.project.jobs[params.jobIndex], {
            [params.field]: params.value
        });
    }
};

const actions = {
    addJob: function (context) {
        context.mit('addJob', state.defaultJob);
    },
    deleteJob: function (context, index) {
        context.mit('deleteJob', index);
    },
    updateJobValue: function (context, params) {
        context.mit('updateJobValue', params);
    },
};

const module = {
    state,
    getters,
    mutations,
    actions
};

export default module;

The project state is mapped to a puted property of my vue instance:

puted: {
       ...mapState({
           project: state => state.jobCreator.project,
       }),
}

The problem is the following: In the image of the application, you can see that I entered "vin" in one of the fields, but all of the fields are updating.

So, all of the function fields of all the jobs have been updated to my last entry, instead of only the one I want.

What am I doing wrong?

PS:

I also tried the following in my mutation function:

updateJobValue(state, params) {
    var job = state.project.jobs[params.jobIndex];
    job[params.field] = params.value;

    Vue.set(state.project.jobs, params.jobIndex, job);
}

But it's giving me the same result.

UPDATE: As requested, I created a jsFiddle to show my problem

Share Improve this question edited Jul 3, 2017 at 14:42 thanksd 55.7k23 gold badges165 silver badges154 bronze badges asked Jul 1, 2017 at 6:40 vincentvincent 1,3234 gold badges16 silver badges31 bronze badges 2
  • Could you possibly turn this into a jsfiddle? Since it is a rather long question it will be much easier for people to help you out that way. – Stephan-v Commented Jul 1, 2017 at 10:19
  • I added a jsfiddle explaining my problem – vincent Commented Jul 3, 2017 at 7:34
Add a ment  | 

2 Answers 2

Reset to default 11 +25

The issue is in your addJob action:

addJob: function (context) {
    context.mit('addJob', state.defaultJob);
},

You are referencing the state.defaultJob object each time you add a new job. That means each item in the state.project.jobs array is referencing the same object.

You should create a copy of the object when passing it to the addJob mutation:

addJob: function (context) {
    context.mit('addJob', Object.assign({}, state.defaultJob));
},

Or, just pass in a new object with the default properties each time:

addJob: function (context) {
    context.mit('addJob', {
        function: '',
        title: '',
        description: '',
        profiles: 1,
        location_id: '',
        category_id: '',
        budget: '',
    });
},

Here's a working fiddle.

Here's a post explaining how variables are passed in Javascript: Javascript by reference vs. by value

I would give the following advice:

Use v-bind:value="job.function instead of v-model="job.function" because you want only a one way binding. This your code more predictable.

Add a v-key="job" to your v-for="(job, index) in project.jobs" element just to be sure that the rendering works correctly.

The first two lines should be enought, the object is still reactive.

var job = state.project.jobs[params.jobIndex];
job[params.field] = params.value;


Vue.set(state.project.jobs, params.jobIndex, job);

PS: In my fiddle the @change did only fire when i hit enter or left the input.

本文标签: javascriptUpdating an item in an array updates them allStack Overflow