Advertisement

#1 How To Communicate Between Parent And Child Components

In this video we discuss how to handle component communication between a parent and one or more children. We will start off by simply passing data from the parent to the child and move on to handling events emitted from the child which the parent can then listen for and respond to. Both of these interactions can be handled very easily by just using the normal tools provided by Vue itself. We will then finish up by discussing a couple of different ways of handling events that take place within the scope of the parent component as using those to trigger actions within the children.

Parts

Code Snippets

Child.vue

<template lang="pug">
div.p-5.bg-blue-100
    ...
    div {{parentMessage}}
</template>
src ⟩ components ⟩ component-communication ⟩ Child.vue

Child.vue

<script lang="ts">
import { Component, Prop, Vue } from "vue-property-decorator";

@Component
export default class Child extends Vue {
    @Prop({ default: "[undefined]" }) private readonly parentMessage!: string;
}
</script>
src ⟩ components ⟩ component-communication ⟩ Child.vue

Parent.vue

<template lang="pug">
div.p-5.bg-green-100
    ...
    input.p-2.w-full.mb-2(v-model="parentMessage")
    div.mb-2 {{parentMessage}}
    Child(v-bind:parentMessage="parentMessage")/
</template>
src ⟩ components ⟩ component-communication ⟩ Parent.vue

Parent.vue

<script lang="ts">
...
export default class Parent extends Vue {
    private parentMessage = "Parent starting message!";
}
</script>
src ⟩ components ⟩ component-communication ⟩ Parent.vue

Child.vue

<template lang="pug">
div.p-5.bg-blue-100
    ...
    div.flex.mb-2
        input.p-2.flex-1(v-model="childMessage")
        button.button(v-on:click.prevent="save") Save
    ...
</template>
src ⟩ components ⟩ component-communication ⟩ Child.vue

Child.vue

<script lang="ts">
...
export default class Child extends Vue {
    ...
    private childMessage = "The child message";

    private save() {
        this.$emit("save", this.childMessage);
    }
}
</script>
src ⟩ components ⟩ component-communication ⟩ Child.vue

Parent.vue

<template lang="pug">
div.p-5.bg-green-100
    ...
    Child(
        v-bind:parentMessage="parentMessage"
        v-on:save="save")/
</template>
src ⟩ components ⟩ component-communication ⟩ Parent.vue

Parent.vue

<script lang="ts">
...
export default class Parent extends Vue {
    ...
    private save(childMessage: string) {
        this.parentMessage = childMessage;
    }
    ...
}
</script>
src ⟩ components ⟩ component-communication ⟩ Parent.vue

Child.vue

<script lang="ts">
import { ..., Watch } from "vue-property-decorator";

export enum Commands {
    None,
    Clear,
}
...
export default class Child extends Vue {
    @Prop({ default: Commands.None }) private readonly command!: Commands;
    ...
    @Watch("command")
    private watchCommand() {
        switch (this.command) {
            case Commands.None:
                console.log("Nothing to do.")
                break;
            case Commands.Clear:
                this.childMessage = "";
                break;
        }
    }
}
</script>
src ⟩ components ⟩ component-communication ⟩ Child.vue

Advertisement

Parent.vue

<template lang="pug">
div.p-5.bg-green-100
    ...
    button.button.mb-2(v-on:click.prevent="clearChildren") Clear
    Child(
        v-bind:command="childCommand"
        v-bind:parentMessage="parentMessage"
        v-on:save="save")/
</template>
src ⟩ components ⟩ component-communication ⟩ Parent.vue

Parent.vue

<script lang="ts">
...
import ..., { Commands } from "@/components/component-communication/Child.vue";
...
export default class Parent extends Vue {
    private childCommand = Commands.None;
    ...
    private clearChildren() {
        this.childCommand = Commands.Clear;
        this.childCommand = Commands.None;
    }
    ...
}
</script>
src ⟩ components ⟩ component-communication ⟩ Parent.vue

Parent.vue

<script lang="ts">
...
export default class Parent extends Vue {
    ...
    private clearChildren() {
        this.childCommand = Commands.Clear;
        requestAnimationFrame(() => {
            this.childCommand = Commands.None;
        });
    }
    ...
}
</script>
src ⟩ components ⟩ component-communication ⟩ Parent.vue

observable.ts

type Subscription<T> = (x: T) => void;

export class Observable<T> {
    private callbacks: Array<Subscription<T>> = [];

    public next(input: T) {
        this.callbacks.forEach((x) => x(input));
    }

    public subscribe(subscription: Subscription<T>) {
        this.callbacks.push(subscription);
    }
}
src ⟩ components ⟩ component-communication ⟩ observable.ts

Child.vue

<script lang="ts">
...
import { Observable } from "@/components/component-communication/observable";
...
export default class Child extends Vue {
    @Prop() private readonly observable!: Observable<Commands>;
    ...
    private mounted() {
        this.observable.subscribe(this.runCommand);
    }

    private runCommand(command: Commands) {
        switch (command) {
            case Commands.None:
                console.log("Nothing to do.");
                break;
            case Commands.Clear:
                this.childMessage = "";
                break;
        }
    }
    ...
}
</script>
src ⟩ components ⟩ component-communication ⟩ Child.vue

Parent.vue

<template lang="pug">
div.p-5.bg-green-100
    ...
    Child(
        v-bind:observable="observable"
        v-bind:parentMessage="parentMessage"
        v-on:save="save")/
</template>
src ⟩ components ⟩ component-communication ⟩ Parent.vue

Parent.vue

<script lang="ts">
...
import { Observable } from "@/components/component-communication/observable";
...
export default class Parent extends Vue {
    private observable = new Observable<Commands>();
    ...
    private clearChildren() {
        this.observable.next(Commands.Clear);
    }
    ...
}
</script>
src ⟩ components ⟩ component-communication ⟩ Parent.vue

Exciton Interactive LLC
Advertisement