boyjarv's avatar

Unexpected mutation of "assignment" prop

I am following along on the Learn Vue 3 Laracast courses here: https://laracasts.com/series/learn-vue-3-step-by-step/episodes/7

The instructor has built the assignment in .js pages, I have redone mine in Vue 3

and now I'm getting: Unexpected mutation of "assignment" prop

Here is my repo: https://github.com/jbiddulph/assignments

Please help?

0 likes
16 replies
Sinnbeck's avatar

Did you already get help solving this once and never marked that thread as solved?

boyjarv's avatar

no, this is a different project similar error

MohamedTammam's avatar

It will work, but mostly you're getting this error because you have vue/no-mutating-props enabled. https://eslint.vuejs.org/rules/no-mutating-props.html

You can add that comment

/* eslint-disable */

At the top of your file to disable eslint on it.

But I recommend to follow the convention and transform your code and not mutating props.

Your AssignmentItem.vue component would like

<input type="checkbox" v-model="$emit('update:modelValue', event.target.value)" class="ml-2"

And in your AssignmentList.vue component

<AssignmentItem
        v-for="assignment in assignments"
        :key="assignment.id"
        :assignment="assignment"
		v-model="assignment.complete"
      />
boyjarv's avatar

I put

v-model="assignment.complete"

in my form input

I am now getting: error 'v-model' directives require the attribute value which is valid as LHS

MohamedTammam's avatar

@boyjarv Sorry, I forget to mention that you need to have modelValue prop in your AssignmentItem.vue component

<template>
  <li>
    <label class="p-2 flex justify-between items-center"
      >{{ assignment.name }}
       <input type="checkbox" :value="modelValue" v-model="$emit('update:modelValue', event.target.value)" class="ml-2"  
	</label>
  </li>
</template>

<script>
export default {
  props: {
    assignment: Object,
   modelValue: String, // Boolean
  },
};
</script>
boyjarv's avatar

@MohamedTammam

AssignmentItem.vue says this:

'v-model' directives require the attribute value which is valid as LHS.

boyjarv's avatar

either true or false, false by default

boyjarv's avatar

Home

<template>
  <div class="home">
    <AssignmentItems />
  </div>
</template>

<script>
import AssignmentItems from "@/components/AssignmentItems.vue";

export default {
  name: "HomeView",
  components: {
    AssignmentItems,
  },
};
</script>

AssignmentsList.vue

<template>
  <section v-show="assignments.length">
    <h2 class="font-bold mb-2">{{ title }}</h2>
    <ul class="border rounded border-gray-600 divide-y divide-gray-600">
      <AssignmentItem
        v-for="assignment in assignments"
        :key="assignment.id"
        :assignment="assignment"
        v-model="assignment.complete"
      />
    </ul>
  </section>
</template>

<script>
import { AssignmentItem } from "@/components/AssignmentItem.vue";
export default {
  components: { AssignmentItem },
  props: {
    assignments: Array,
    title: String,
  },
};
</script>

AssignmentItems.vue

<template>
  <section class="space-y-6">
    <AssignmentList
      :assignments="filters.inProgress"
      title="In Progress"
    ></AssignmentList>
    <AssignmentList
      :assignments="filters.completed"
      title="Completed Assignments"
    ></AssignmentList>
    <form @submit.prevent="add">
      <div class="border border-gray-600 text-black">
        <input
          v-model="newAssignment"
          placeholder="New Assignment"
          class="p-2"
        />
        <button type="submit" class="bg-white p-2 border-l">Add</button>
      </div>
    </form>
  </section>
</template>

<script>
import AssignmentList from "@/components/AssignmentList.vue";
export default {
  components: {
    AssignmentList,
  },
  data() {
    return {
      assignments: [
        { id: 1, name: "do homework", complete: false },
        { id: 2, name: "finish book", complete: false },
        { id: 3, name: "learn code", complete: false },
        { id: 4, name: "Walk the dog", complete: false },
      ],
      newAssignment: "",
    };
  },
  computed: {
    filters() {
      return {
        inProgress: this.assignments.filter(
          (assignment) => !assignment.complete
        ),
        completed: this.assignments.filter((assignment) => assignment.complete),
      };
    },
  },
  methods: {
    add() {
      alert("New assignment added!");
      this.assignments.push({
        name: this.newAssignment,
        completed: false,
        id: this.assignments.length + 1,
      });
    },
  },
};
</script>

AssignmentItem.vue

<template>
  <li>
    <label class="p-2 flex justify-between items-center"
      >{{ assignment.name }}
      // eslint-disable-next-line
      <input
        type="checkbox"
        v-model="$emit('update:modelValue', event.target.value)"
        class="ml-2"
      />
    </label>
  </li>
</template>

<script>
export default {
  props: {
    assignment: Object,
    modelValue: String, // Boolean
  },
};
</script>

AppButton.vue

<template>
  <button
    :class="{
      'border rounded p-5 py-2 disabled:cursor-not-allowed disabled:bg-red-300': true,
      'bg-blue-300 hover:bg-blue-500': type === 'primary',
      'bg-green-300 hover:bg-green-500': type === 'secondary',
      'bg-red-300 hover:bg-red-500': type === 'danger',
      'bg-yellow-300 hover:bg-yellow-500': type === 'warning',
      'is-loading': processing,
    }"
    :disabled="processing"
  >
    <slot />
  </button>
</template>

<script>
export default {
  props: {
    type: {
      type: String,
      default: "primary",
    },
    processing: {
      type: Boolean,
      default: false,
    },
  },
};
</script>

MohamedTammam's avatar
Level 51

@boyjarv Sorry, change your input in the AssignmentItem.vue component to be

<input
        type="checkbox"
		:value="modelValue"
		@input="$emit('update:modelValue', event.target.value)"
        class="ml-2"
      />

Please or to participate in this conversation.