blacksoul
blacksoul

Reputation: 43

How to get data resolved in parent component

I'm using Vue v1.0.28 and vue-resource to call my API and get the resource data. So I have a parent component, called Role, which has a child InputOptions. It has a foreach that iterates over the roles.

The big picture of all this is a list of items that can be selected, so the API can return items that are selected beforehand because the user saved/selected them time ago. The point is I can't fill selectedOptions of InputOptions. How could I get that information from parent component? Is that the way to do it, right?

I pasted here a chunk of my code, to try to show better picture of my problem:

role.vue

<template>
    <div class="option-blocks">
    <input-options
        :options="roles"
        :selected-options="selected"
        :label-key-name.once="'name'"
        :on-update="onUpdate"
        v-ref:input-options
    ></input-options>
    </div>
</template>

<script type="text/babel">
    import InputOptions from 'components/input-options/default'
    import Titles from 'steps/titles'

    export default {
        title: Titles.role,
        components: { InputOptions },
        methods: {
            onUpdate(newSelectedOptions, oldSelectedOptions) {
                this.selected = newSelectedOptions
            }
        },

        data() {
            return {
                roles: [],
                selected: [],
            }
        },

        ready() {
            this.$http.get('/ajax/roles').then((response) => {
                this.roles = response.body
                this.selected = this.roles.filter(role => role.checked)
            })
        }
    }
</script>

InputOptions

<template>
    <ul class="option-blocks centered">
        <li class="option-block" :class="{ active: isSelected(option) }" v-for="option in options" @click="toggleSelect(option)">
            <label>{{ option[labelKeyName] }}</label>
        </li>
    </ul>
</template>

<script type="text/babel">
    import Props from 'components/input-options/mixins/props'

    export default {
        mixins: [ Props ],
        computed: {
            isSingleSelection() {
              return 1 === this.max
            }
        },
        methods: {
            toggleSelect(option) {
                //...
            },
            isSelected(option) {
                return this.selectedOptions.includes(option)
            }
        },

        data() {
            return {}
        },

        ready() {
            // I can't figure out how to do it
            // I guess it's here where I need to get that information,
            // resolved in a promise of the parent component
            this.$watch('selectedOptions', this.onUpdate)
        }
    }
</script>

Props

export default {
    props: {
        options: {
            required: true
        },
        labelKeyName: {
            required: true
        },
        max: {},
        min: {},
        onUpdate: {
            required: true
        },
        noneOptionLabel: {},
        selectedOptions: {
            type: Array
            default: () => []
        }
    }
}

EDIT

I'm now getting this warning in the console:

[Vue warn]: Data field "selectedOptions" is already defined as a prop. To provide default value for a prop, use the "default" prop option; if you want to pass prop values to an instantiation call, use the "propsData" option. (found in component: <default-input-options>)

Upvotes: 0

Views: 209

Answers (2)

blacksoul
blacksoul

Reputation: 43

Finally, I found the bug. I wasn't binding the prop as kebab-case

Upvotes: 0

Mani Jagadeesan
Mani Jagadeesan

Reputation: 24265

Are you using Vue.js version 2.0.3? If so, there is no ready function as specified in http://vuejs.org/api. You can do it in created hook of the component as follows:

// InputOptions component
// ...
data: function() {
    return {
        selectedOptions: []
    }
},
created: function() {
    this.$watch('selectedOptions', this.onUpdate)
}

In your InputOptions component, you have the following code:

this.$watch('selectedOptions', this.onUpdate)

But I am unable to see a onUpdate function defined in methods. Instead, it is defined in the parent component role. Can you insert a console.log("selectedOptions updated") to check if it is getting called as per your expectation? I think Vue.js expects methods to be present in the same component.

Alternatively in the above case, I think you are allowed to do this.$parent.onUpdate inside this.$watch(...) - something I have not tried but might work for you.

EDIT: some more thoughts

You may have few more issues - you are trying to observe an array - selectedOptions which is a risky strategy. Arrays don't change - they are like containers for list of objects. But the individual objects inside will change. Therefore your $watch might not trigger for selectedOptions.

Based on my experience with Vue.js till now, I have observed that array changes are registered when you add or delete an item, but not when you change a single object - something you need to verify on your own.

To work around this behaviour, you may have separate component (input-one-option) for each of your input options, in which it is easier to observe changes.

Upvotes: 1

Related Questions