0

I must be doing something wrong when trying to access the data of my child component.

I have two sets of data : targets and comparators. They can be updated with inputs by the user. Computed props update the data of the child component, and then I wanted to emit an event to the parent component thanks to the watchers I put on these two sets of data. However, these watchers seems to never be triggered..

This how the script of the child component looks like (remark, I only pasted two computed props):

<script>
    export default {
        name: "Targets",
        props: ['mealPlan'],
        data() {
            return {
                targets:{
                    weight: 0,
                    calories: 0,
                    carbs: 0,
                    proteins: 0,
                    fats: 0,
                    sugar: 0,
                    fibers: 0,
                    cholesterol: 0,
                    calcium: 0,
                    iron: 0,
                    sodium: 0,
                    potassium: 0,
                    cost: 0,
                    vitaminA: 0,
                    vitaminB6: 0,
                    vitaminB12: 0,
                    vitaminC: 0,
                    vitaminD: 0,
                    vitaminE: 0,
                    vitaminK: 0
                },
                comparators:{
                    weight: 0,
                    calories: 0,
                    carbs: 0,
                    proteins: 0,
                    fats: 0,
                    sugar: 0,
                    fibers: 0,
                    cholesterol: 0,
                    calcium: 0,
                    iron: 0,
                    sodium: 0,
                    potassium: 0,
                    cost: 0,
                    vitaminA: 0,
                    vitaminB6: 0,
                    vitaminB12: 0,
                    vitaminC: 0,
                    vitaminD: 0,
                    vitaminE: 0,
                    vitaminK: 0
                }
            }
        },
        computed:{
            weightTarget:{
                get:function(){
                    this.targets.weight = this.mealPlan.targetWeight;
                    return this.mealPlan.targetWeight;
                },
                set:function(newValue){
                    this.targets.weight = newValue
                }
            },


            weightComparator:{
                get:function(){
                    this.comparators.weight = this.mealPlan.comparatorWeight;
                    return this.mealPlan.comparatorWeight;
                },
                set:function(newValue){
                    this.comparators.weight = newValue
                }
            },

        },
        watch:{
            targets:function(){
                console.log(this.targets);
                this.$emit('targetsUpdated', this.targets);
            },
            comparators:function(){
                this.$emit('comparatorsUpdated', this.comparators);
            }
        }
    }
</script>

The parent component receives the event like this :

<template>
    <div>
        <button @click="save" type="button" class="btn btn-success pull-left">Save</button>

        <div>

                <b-tab title="Targets">
                    <Targets
                    :meal-plan="mealPlan"
                    @targetsUpdated="targetsUpdated"
                    @comparatorsUpdated="comparatorsUpdated"
                    ></Targets>
                </b-tab>
        </div>
    </div>
</template>

<script>
    import MealTable from "../components/MealTable";
    import DayTable from "../components/DayTable";
    import Targets from "./Targets";
    import Specifications from "./Specifications";

    export default {
        name: "Edit",
        components: {DayTable, MealTable,Targets,Specifications},
        data(){
            return{
                mealPlan: {},
                currentDay: '1',
                targets:{},
                comparators:{},
            }
        },

        computed: {

        methods:{
            targetsUpdated(newTargets){
                this.targets = {
                    weight: newTargets.targetWeight,
                    calories: newTargets.targetCalories,
                    carbs: newTargets.targetCarbs,
                    proteins: newTargets.targetProteins,
                    fats: newTargets.targetFats,
                    sugar: newTargets.targetSugar,
                    fibers: newTargets.targetFibers,
                    cholesterol: newTargets.targetCholesterol,
                    calcium: newTargets.targetCalcium,
                    iron: newTargets.targetIron,
                    sodium: newTargets.targetSodium,
                    potassium: newTargets.targetPotassium,
                    cost: newTargets.targetCost,
                    vitaminA: newTargets.targetVitaminA,
                    vitaminB6: newTargets.targetVitaminB6,
                    vitaminB12: newTargets.targetVitaminB12,
                    vitaminC: newTargets.targetVitaminC,
                    vitaminD: newTargets.targetVitaminD,
                    vitaminE: newTargets.targetVitaminE,
                    vitaminK: newTargets.targetVitaminK
                }
            },
            comparatorsUpdated(newComparators){
                this.comparators = {
                    weight: newComparators.comparatorWeight,
                    calories: newComparators.comparatorCalories,
                    carbs: newComparators.comparatorCarbs,
                    proteins: newComparators.comparatorProteins,
                    fats: newComparators.comparatorFats,
                    sugar: newComparators.comparatorSugar,
                    fibers: newComparators.comparatorFibers,
                    cholesterol: newComparators.comparatorCholesterol,
                    calcium: newComparators.comparatorCalcium,
                    iron: newComparators.comparatorIron,
                    sodium: newComparators.comparatorSodium,
                    potassium: newComparators.comparatorPotassium,
                    cost: newComparators.comparatorCost,
                    vitaminA: newComparators.comparatorVitaminA,
                    vitaminB6: newComparators.comparatorVitaminB6,
                    vitaminB12: newComparators.comparatorVitaminB12,
                    vitaminC: newComparators.comparatorVitaminC,
                    vitaminD: newComparators.comparatorVitaminD,
                    vitaminE: newComparators.comparatorVitaminE,
                    vitaminK: newComparators.comparatorVitaminK
                }
            }
        }
    }
</script>

To sum up, I do not understand while the watcher on targets or comparators is not triggered, thanks for the help guys !

3
  • flag them deep:true - but honestly emit in setter? Commented Jan 24, 2020 at 6:04
  • Does this answer your question? Vue.js - How to properly watch for nested data Commented Jan 24, 2020 at 6:46
  • @Estradiaz what do you suggest ? Commented Jan 24, 2020 at 7:01

2 Answers 2

2

So when you watch an array or an object, Vue has no idea that you've changed what's inside that data. You have to tell Vue that you want it to inspect inside of the data when watching for changes.

You can do this by setting deep to true on your watcher and rearranging the handler function.

watch: {
    targets: {
      // This will let Vue know to look inside the object
      deep: true,

      // We have to move our method to a handler field
      handler()
        this.$emit('targetsUpdated', this.targets);
      }
    },
    comparators: {
      // This will let Vue know to look inside the object
      deep: true,

      // We have to move our method to a handler field
      handler()
        this.$emit('comparatorsUpdated', this.comparators);
      }
    }
 }
Sign up to request clarification or add additional context in comments.

Comments

0

In addition to the usage of watchers one can simply add the same logic to the setters:

e.g:

       weightComparator:{
            get:function(){
                this.comparators.weight = this.mealPlan.comparatorWeight;
                return this.mealPlan.comparatorWeight;
            },
            set:function(newValue){
                let oldValue = this.comparators.weight
                this.$emit('change:comparators:weight', newValue, oldValue)
                let oldComparators = Object.assign({}, this.comparators) // shallow copy
                this.comparators.weight = newValue
                this.$emit('changed:comparators', Object.assign({}, this.comparators), oldComparators)                                          

            }
        },

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.