Vue.js – push data from nested childs to parent

Last time I work with Node and Vue.js. It’s very nice and allows to simplify many, many things. And it’s a lot better – for me – than React and its code mess… One of very nice features from Vue is components. We can separate code into small modules and then import and use them in another as blocks. We can also send some data to them, but direct data binding is only in one way – from parents to childs. According to official documentation, we should use events to notify parents about changes in childs and then make changes. But what about nested childs?

Let’s say we have nested data structure from our API, database, file, nevermind. It’s an good example:

{
    name: 'parent1',
    value: 1,
    childs: [
        {
            name: 'child1',
            value: 11,
            childs: [
                {
                    name: 'childchild1',
                    value: 111
                },
                {
                    name: 'childchild2',
                    value: 112
                },
            ]
        },
                {
            name: 'child2',
            value: 12,
            childs: [
                {
                    name: 'childchild2',
                    value: 121
                },
        
            ]
        }
    ]
}

We want to create two Vue components. One with our parent, and one for all childs. We can do this and control all childs using only one, nested component. It’s an example of parent component:

<template>
    <div>
      <child 
        v-for="(child, index) in getChilds"
        v-bind:currentElement="child"
        v-bind:key="index"
      ></child>
        
    <!-- Other code -->
    </div>
</template>


<script>
import ComponentChild from 'path/to/child'

export default {
    components: {
        'child': ComponentChild,
    },
    computed: {
        getChilds: function () {

            // Maybe some filter, etc?
            return this.childs || []
        }
    }

Now we can use similar code in our child component. Of course we will use props, but there is something else… we use child component inside child component – why not?

<template>
    <section>
      <child 
        v-for="(child, index) in getChilds"
        v-bind:currentElement="child"
        v-bind:key="index"
      ></child>
        
    <!-- Other code -->
    </section>
</template>


<script>
export default {
    props: [ 'currentElement' ],
    components: {
        'child': ComponentChild,
    },
    computed: {
        getChilds: function () {

            // Maybe some filter, etc?
            return this.currentElement.childs || []
        }
    }

And it’s all – we have nested child. It will work not only for one or two levels, but many, many. Ok, but what about data binding? We have props from parent to child and from higher to lower child level, but we can’t do anything in parent on childs changes. Let’s change this, first on parent template:

  <child 
        v-for="(child, index) in getChilds"
        v-bind:currentElement="child"
        v-on:callChange="changeFromChild"
        v-bind:key="index"
 ></child>

(...)


<script>
export default {
    methods: {
        changeFromChild (foo, bar) {
            console.log('Child has sent me ' + foo + ' and ' + bar)
        }
    }

And also similar in child – now we can use event emit to “do the magic”:

  <child 
        v-for="(child, index) in getChilds"
        v-bind:currentElement="child"
        v-on:callChange="changeFromChild"
        v-bind:key="index"
 ></child>

(...)

<script>
export default {
    methods: {
        changeFromChild (foo, bar) {
            // Send received data to parent
            this.$emit('callChange', foo, bar)
        }

        myCustomMethod () {
            this.$emit('callChange', 'apple', 'banana')
        }
    }

And now it’s complete. We have changeFromChild method in child component and also example method (myCustomMethod) to call this. Let’s say we call it from lowest level child. It will emit callChange event to higher level and then… This child-parent will also emit event to higher level etc. In result, parent will have information about changes and can react to them.

What about identify child or nesting level? You can use index key which we have to bind.