Юрий Яхница
Юрий Яхница

Reputation: 427

Can't set object property as reactive in Vue.js

I have one file vue component with one property 'todo-item' with such structure

{
  id:1,
  text:'Buy tickets',
  isDone: false,
  person:'Boss',
  location:'Boryspil',
  childTask:null,
},

And I have computed properties:

computed:{ 
  hasLocation(){
      return this.todoItem.location;
  },
  hasPerson(){
      return this.todoItem.person;
  },
  hasChildTask(){
      return this.todoItem.childTask;
  },
  hasParentTask(){
      return true;
  },
}

And I want to make all of object properties reactive, but when I change properties in method:

deletePerson(){
  this.$set(this.todoItem, 'person', null);
  console.log(this.hasPerson);
  console.log(this.todoItem.person);
},

todoItem.person is still not reactive, this.hasPerson have old value, and this.todoItemPerson shows null value. I tried to make them reactive on created method, but it's still not reactive.

This is by component whole js code, without template and css for short:

    <script>
    import HoveredChip from "@/components/HoveredChip";
    import {mapMutations} from 'vuex';
    export default {
        name: "TodoItem",
        components: {HoveredChip},
        props:['todo-item'],
        data() {
            return{
                isActive : true,
            }
        },
        computed:{

            hasLocation(){
                return this.todoItem.location;
            },
            hasPerson(){
                return this.todoItem.person;
            },
            hasChildTask(){
                return this.todoItem.childTask;
            },
            hasParentTask(){
                return true;
            },
            people(){
                return [
                    "dad",
                    "Ann",
                    "boss",
                    "prostitute"
                ]
            },
            places(){
                return []
            }
        },
        methods:{
            ...mapMutations(['addPersonMutation'],{

            }),
            moveToPerson(){

            },
            moveToLocation(){

            },
            moveToPatentTask(){

            },
            addLocation(){

            },
            addPerson(val){
                this.addPersonMutation(val);
                this.$set(this.todoItem,'person',val);
                console.log(this.hasPerson);
                console.log(this.todoItem.person);
            },

            addChildTask(){

            },
            deletePerson(){
                this.$set(this.todoItem, 'person', null);
                console.log(this.hasPerson);
                console.log(this.todoItem.person);
            },
            deleteLocation(){

            },
            deleteChildTask(){

            },
            editLocation(){

            },
            savePerson(){

            },
            editChildTask(){

            }

        },
        created(){
            // this.$set(this.todoItem, 'person', 'undefined');
            // this.$set(this.todoItem, 'location', '????');
            // this.$set(this.todoItem, 'isDone', "....");
        }
    }
</script>

Upvotes: 0

Views: 2675

Answers (2)

Юрий Яхница
Юрий Яхница

Reputation: 427

My problem was in props, I get todoItem from parent element, and I can't do it reactive, but with deep watch all object properties becomes reactive. I solved my problem just adding watch property to my component:

And now when I change person (or any other) property of my todoItem changes updates in computed properties either.

    watch:{
        todoItem:{
            deep: true,
            handler(){
                this.saveTodoAction(this.todoItem);
            }
        }
    },

And this is the whole code:

import HoveredChip from "@/components/HoveredChip";
import {mapMutations, mapActions} from 'vuex';
export default {
    name: "TodoItem",
    components: {HoveredChip},
    props:['todo-item'],
    data() {
        return{
            isActive : true,
        }
    },
    computed:{

        hasLocation(){
            return this.todoItem.location;
        },
        hasPerson(){
            return this.todoItem.person;
        },
        hasChildTask(){
            return this.todoItem.childTask;
        },
        hasParentTask(){
            return true;
        },
        people(){
            return [
                "Dad",
                "Ann",
                "Boss",
                "Prostitute"
            ]
        },
        places(){
            return []
        }
    },
    methods:{
        ...mapMutations(['addPersonMutation'],{

        }),
        ...mapActions(['saveTodoAction']),
        moveToPerson(){

        },
        moveToLocation(){

        },
        moveToPatentTask(){

        },
        addLocation(){

        },
        addPerson(val){
            this.addPersonMutation(val);
        },

        addChildTask(){

        },
        deletePerson(){
            this.todoItem.person = null;
        },
        deleteLocation(){

        },
        deleteChildTask(){

        },
        editLocation(){

        },
        savePerson(){

        },
        editChildTask(){

        },

    },
    watch:{
        todoItem:{
            deep: true,
            handler(){
                this.saveTodoAction(this.todoItem);
            }
        }
    },
    created(){
    }
}

Upvotes: 0

MAW
MAW

Reputation: 973

The issue is with your property name. Change the 'todo-item' in the data section to todoItem.

This works

<template>
    <div>
        <button @click.prevent="printPerson">Print Person</button>
        <br />
        <button @click.prevent="deletePerson">Delete Person</button>
    </div>
</template>

<script>
    export default {
        data: () => ({
            todoItem: {
                id: 1,
                text: 'Buy tickets',
                isDone: false,
                person: 'Boss',
                location: 'Boryspil',
                childTask: null,
            },

        }),
        computed: {
            hasLocation() {
                return this.todoItem.location;
            },
            hasPerson() {
                return this.todoItem.person;
            },
            hasChildTask() {
                return this.todoItem.childTask;
            },
            hasParentTask() {
                return true;
            },
        },

        methods: {
            deletePerson() {
                this.$set(this.todoItem, 'person', null);
                // this.todoItem.person = "null"
                console.log(this.hasPerson);
                console.log(this.todoItem.person);
            },
            printPerson() {
                console.log(this.hasPerson);
                console.log(this.todoItem.person);
            }
        }
    }
</script>

Also, using "this.todoItem.person = null" works.

If still doesn't work for you, edit your question and add the complete component code and we can help.

Upvotes: 4

Related Questions