Calling parent component method from child component written in Jsx Vue - javascript

I didn't expect it be tough.
I've a child component written like
InputWrapper.vue
<script>
import StyledInput from "./input";
export default {
name: "MyInput",
props: {
multiline: Boolean,
onChange: Function
},
render(h) {
const { multiline, onChange } = this;
console.log(onChange);
return (
<div>
<StyledInput multiline={multiline} onChange={e => onChange(e)} />
</div>
);
}
};
</script>
Then I have actual input as vue-styled-components as Input.js. For those familiar with styled components need not explain that code.
Then I consume this InputWrapper component in my parent component Home.vue
<template>
<div class="pLR15 home">
<Row>
<MyInput :multiline="true" placeholder="Sample Input" type="text" :onChange="handleChange"></MyInput>
</Row>
</div>
</template>
<script>
// # is an alias to /src
import HelloWorld from "#/components/HelloWorld.vue";
import Row from "#/ui_components/row";
import MyInput from "#/ui_components/form/input/index.vue";
export default {
name: "home",
components: {
HelloWorld,
Row,
MyInput
},
methods: {
handleChange: function(e) {
console.log("Hey you are changing my value to", e.target.value);
}
}
};
</script>
Problem - onChange on parent is not fired.

#change.native="handleChange" did the trick for me. Also I cleaned up all the event handlers listening on child. Since my type and placeholder properties were passing down as such, so should be the event listeners. With that thought the .native modifier works best for now. Although things could have been uniform by just #change="handleChange" which I was trying earlier and lead to trying out passing function as props to child.
IMP NOTE - Vuejs doesn't treats #change as normal onChange. #input is preferred if the idea is to capture every keystroke. Here comes the opinions! :)

Related

Child component emits an event I didn't ask for in Vue 3

I'm in the process of migrating my medium-sized app from Vue2 to Vue3.
I noticed that Vue3 Child-Parent emit mechanism is different compared to Vue2 and confuses me a lot.
Here's a basic example for demonstration
// App.vue
<script>
import InputWrap from './InputWrap.vue';
export default {
name: 'App',
components: {
InputWrap,
},
data() {
return {
msg: 'Hello world',
}
},
methods: {
onChange() {
console.log('why change?');
}
}
}
</script>
<template>
<h1>{{ msg }}</h1>
<input-wrap v-model="msg" #change="onChange" />
</template>
// InputWrap.vue
<script>
import MyInput from './MyInput.vue';
export default {
name: 'InputWrap',
components: {
MyInput,
},
props: ['modelValue'],
methods: {
onUpdate(v) {
this.$emit('update:modelValue', v);
}
}
}
</script>
<template>
<my-input :modelValue="modelValue" #update:modelValue="onUpdate" />
</template>
// MyInput.vue
<script>
export default {
name: 'MyInput',
props: {
modelValue: String,
},
methods: {
onInput(e) {
this.$emit('update:modelValue', e.target.value);
}
}
}
</script>
<template>
<input :value="modelValue" #input="onInput" />
</template>
Link to Vue SFC playground.
I'm curious why does onChange event handler is called in App.vue?
It seems that change event is generated by input element in MyInput.vue. But it's totally not transparent why this event is going up through all components and being captured in App.vue. Imagine a tree with dozens nested components and a root component listening for change event. It's a total mess.
Vue2 have a different approach and I like it because it has a transparent child-parent communication. Is it possible to turn on Vue2 emit mechanism in Vue3?
The reason is that Vue implements Fallthrough Attributes mechanism
A "fallthrough attribute" is an attribute or v-on event listener that is passed to a component, but is not explicitly declared in the receiving component's props or emits.
When a component renders a single root element, fallthrough attributes will be automatically added to the root element's attributes
In your example, your component meets 2 conditions:
InputWrap.vue render a single root element (MyInput.vue components)
InputWrap.vue does not declare onChange as the component's emits
The same with MyInput.vue component
So the #change listener will fall through to the input element.
To disable fallthrough attributes you can declare the attributes as the props/emits of the child component or disable the whole feature for that component by adding inheritAttrs: false:
// InputWrap.vue
<script>
import MyInput from './MyInput.vue';
export default {
name: 'InputWrap',
components: {
MyInput,
},
inheritAttrs: false
}
</script>
SFC link
Vue 2 only inherit attributes

Conditional template rendering with props in Vue3?

I'm trying to make a toggle button so that a hamburger menu opens when clicked.
I made the boolean "clicked" property in "App.vue", passed it down to "Navbar.vue", and now I want to be able to click in the navbar to toggle the "clicked" property to "true" or "false" to make the backdrop and drawer show or not show.
I tried to use an "emit", and it seems to work, but the template isn't responding to the "clicked" variable and is showing even though it's false.
In the code below, what part did I get wrong? How do you implement conditional rendering with props? Can someone help?
App.vue
<template>
<NavBar :clicked="clicked" #toggleDrawer="toggleMenu()" />
<BackDrop :clicked="clicked" />
<SideDrawer :clicked="clicked" />
<router-view></router-view>
</template>
<script>
export default {
name: "App",
components: { NavBar, BackDrop, SideDrawer },
setup() {
const clicked = ref(false);
const toggleMenu = () => {
clicked.value = !clicked.value;
};
return { clicked, toggleMenu };
},
};
</script>
NavBar.vue
<template>
<nav class="navbar">
/* MORE CODE */
<div class="hamburger_menu" #click="toggleEvent">
<div></div>
<div></div>
<div></div>
</div>
</nav>
</template>
<script setup>
import { defineEmits, defineProps } from "vue";
const props = defineProps({
clicked: Boolean,
});
const emit = defineEmits(["toggleDrawer"]);
const toggleEvent = () => {
console.log("toggleEvent running");
emit("toggleDrawer", !props.clicked);
};
</script>
Backdrop.vue
<template v-if="props.clicked">
<div class="backdrop"></div>
</template>
<script setup>
import { defineProps } from "vue";
// eslint-disable-next-line no-unused-vars
const props = defineProps({
clicked: Boolean,
});
</script>
SideDrawer.vue
<template v-if="props.clicked">
<div class="sidedrawer"></div>
</template>
<script setup>
import { defineProps } from "vue";
const props = defineProps({
clicked: Boolean,
});
</script>
Am I passing in the prop wrong? Does "props.clicked" not work in "v-if"'s or templates? How should I implement the "v-if" with the "clicked" property I have?
As #neha-soni said,
After running the code, it is working fine
Vue recommends to use kebab-cased event listeners in templates. Your toggleDrawer will auto-converted into kebab case when you use it in the parent component. So In app.vue you can use it like #toggle-drawer,
<NavBar :clicked="clicked" #toggle-drawer="toggleMenu()" />
From vue doc link
event names provide an automatic case transformation. Notice we emitted a camelCase event, but can listen for it using a kebab-cased listener in the parent. As with props casing, we recommend using kebab-cased event listeners in templates.
After running the code, it is working fine. I have a few feedbacks to remove unnecessary code which is creating confusion and then you can see its working.
Because props are immutable (read-only) in the child component that means their value will not be changed so there is no point to pass props value back (by doing emit("toggleDrawer", !props.clicked)) to the parent because the parent already has their original status.
Another point is, you are passing the data (props data) from the event by doing emit("toggleDrawer", !props.clicked) but not using it when calling the function #toggleDrawer="toggleMenu()" in App.vue, so better to remove this data passing code.
The clicked property is updating in the parent (App.vue) as well as inside the child components. Just console and print the clicked property in the child and parent template like {{ clicked }} at the top and you can see the updated status-
const toggleMenu = () => {
console.log('Before______', clicked.value)
clicked.value = !clicked.value;
console.log('After______', clicked.value)
};

how to replace this v-model pattern in react hooks

Migrating my vue application into react. In vue 2, using a v-model on a component was an equivalent of passing a value prop and emitting an input event.
If we wanted to change prop or event names to something different, we would need to add a model option to ChildComponent component.
Here is my vue child component:
export default {
model: {
prop: 'checked',
event: 'change'
},
props: {
value: String,
checked: {
type: [Boolean, String, Array],
},
}
}
In Parent component i am using like this.
<ChildComponent :checked="SelectedFiles" />
I want to know how to handle this pattern in react hooks. I am not that much familiar with react. Any guidance will be helpful for me.
You could use useState react hook.
For example:
export const MyComponent = () => {
const [value, setValue] = useState('');
return (
<input
type="text"
value={value}
className="form-control"
placeholder="Search..."
onChange={(event) => setValue(event.target.value)}
/>
);
};

How to access native HTML element in template of functional component in Vue.js?

I'm trying to create a custom checkbox component with the Vue.js 2.6. I want to make it stateless, so it takes value as a prop, and creates event to the parent component on the user input, and doesn't hold any data itself.
This is my single-file component (simplified):
<script lang="ts">
import Vue from 'vue';
export default Vue.extend({
functional: true,
props: {
value: {
type: Boolean,
default: false,
},
},
});
</script>
<template functional lang="pug">
label
input(type="checkbox" :checked="value" ref="input"
//-#input="(listeners['input'] || (() => {}))($refs.input.checked)")
#input="(listeners['input'] || (() => {}))($event.target.checked)")
</template>
Which generates this render function:
var render = function(_h, _vm) {
var _c = _vm._c
return _c("label", [
_c("input", {
ref: "input",
attrs: { type: "checkbox" },
domProps: { checked: _vm.value },
on: {
input: (_vm.listeners["input"] || function() {})(
//_vm.$refs.input.checked
_vm.$event.target.checked // Got error on this line
)
}
})
])
}
var staticRenderFns = []
render._withStripped = true
Parent component:
<template lang="pug">
form
checkbox(:value="value" #input="value = $event")
//-checkbox(v-model="value") - also should work
</template>
<script lang="ts">
import Vue from 'vue';
import { default as Checkbox } from './checkbox.vue';
export default Vue.extend({
components: {
checkbox: Checkbox,
},
data() {
return { value: false };
},
});
</script>
When native input element creates an input event, I want to pass the checked property of the input to the parent component listener (if it is exists).
I have tried to use $event.target.checked and $refs.input.checked in the event handler to get the checked property, but realized that I haven't direct access to them in a functional template:
TypeError: "_vm.$refs is undefined"
So, is there a way to access a native HTML element, that creates an event, in attached to it event handler, in a functional component template? I have searched documentation for this topic, but didn't find much.
Or should I just use a stateful component in this case?
You can, but not in an expected way. The thing is with functional components that they pass their refs up the tree. So your ref 'input' will appear in the component that includes your functional checkbox. If you try to attach a ref using template on your functional component, it will simply fail.
So the following wouldn't work (in your parent component), ref 'check' will not be there. But ref 'input' will be, at least the last one, if you put multiple checkboxes.
<form>
<functional-checkbox ref="check" :value="myValue" #input="myValue = $event"/>
</form>
But the following will
<form>
<functional-checkbox :value="myValue" #input="myValue = $event"/>
</form>
// later in code (assuming functional-checkbox has ref="input" defined inside)
this.$refs.input // will have a value, when the component is _mounted_
Regarding your problem with a functional checkbox component - there is a much simpler fix. You just need to define your handler as a function call as it is understood by Vue template compiler. It's not perfect, which is why despite you having created a function call, it is not being interpreted as such.
So you would need to simplify your function call a bit like this
<template functional>
<label>
<input type="checkbox" :checked="props.value"
#input="listeners.input && listeners.input($event.target.checked)">
</label>
</template>
Which would be interpreted as desired
var render = function(_h, _vm) {
var _c = _vm._c
return _c("label", [
_c("input", {
attrs: { type: "checkbox" },
domProps: { checked: _vm.props.value },
on: {
input: function($event) {
_vm.listeners.input && _vm.listeners.input($event.target.checked)
}
}
})
])
}
You can take a more detailed look here, if you're interested about how exactly this render function comes to be
https://github.com/vuejs/vue/blob/dev/packages/vue-template-compiler/browser.js#L4169

vuejs update parent data from child component

I'm starting to play with vuejs (2.0).
I built a simple page with one component in it.
The page has one Vue instance with data.
On that page I registered and added the component to html.
The component has one input[type=text]. I want that value to reflect on the parent (main Vue instance).
How do I correctly update the component's parent data?
Passing a bound prop from the parent is not good and throws some warnings to the console. They have something in their doc but it is not working.
Two-way binding has been deprecated in Vue 2.0 in favor of using a more event-driven architecture. In general, a child should not mutate its props. Rather, it should $emit events and let the parent respond to those events.
In your specific case, you could use a custom component with v-model. This is a special syntax which allows for something close to two-way binding, but is actually a shorthand for the event-driven architecture described above. You can read about it here -> https://v2.vuejs.org/v2/guide/components.html#Form-Input-Components-using-Custom-Events.
Here's a simple example:
Vue.component('child', {
template: '#child',
//The child has a prop named 'value'. v-model will automatically bind to this prop
props: ['value'],
methods: {
updateValue: function (value) {
this.$emit('input', value);
}
}
});
new Vue({
el: '#app',
data: {
parentValue: 'hello'
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.js"></script>
<div id="app">
<p>Parent value: {{parentValue}}</p>
<child v-model="parentValue"></child>
</div>
<template id="child">
<input type="text" v-bind:value="value" v-on:input="updateValue($event.target.value)">
</template>
The docs state that
<custom-input v-bind:value="something" v-on:input="something = arguments[0]"></custom-input>
is equivalent to
<custom-input v-model="something"></custom-input>
That is why the prop on the child needs to be named value, and why the child needs to $emit an event named input.
In child component:
this.$emit('eventname', this.variable)
In parent component:
<component #eventname="updateparent"></component>
methods: {
updateparent(variable) {
this.parentvariable = variable
}
}
From the documentation:
In Vue.js, the parent-child component relationship can be summarized as props down, events up. The parent passes data down to the child via props, and the child sends messages to the parent via events. Let’s see how they work next.
How to pass props
Following is the code to pass props to a child element:
<div>
<input v-model="parentMsg">
<br>
<child v-bind:my-message="parentMsg"></child>
</div>
How to emit event
HTML:
<div id="counter-event-example">
<p>{{ total }}</p>
<button-counter v-on:increment="incrementTotal"></button-counter>
<button-counter v-on:increment="incrementTotal"></button-counter>
</div>
JS:
Vue.component('button-counter', {
template: '<button v-on:click="increment">{{ counter }}</button>',
data: function () {
return {
counter: 0
}
},
methods: {
increment: function () {
this.counter += 1
this.$emit('increment')
}
},
})
new Vue({
el: '#counter-event-example',
data: {
total: 0
},
methods: {
incrementTotal: function () {
this.total += 1
}
}
})
Child Component
Use this.$emit('event_name') to send an event to the parent component.
Parent Component
In order to listen to that event in the parent component, we do v-on:event_name and a method (ex. handleChange) that we want to execute on that event occurs
Done :)
I agree with the event emitting and v-model answers for those above. However, I thought I would post what I found about components with multiple form elements that want to emit back to their parent since this seems one of the first articles returned by google.
I know the question specifies a single input, but this seemed the closest match and might save people some time with similar vue components. Also, no one has mentioned the .sync modifier yet.
As far as I know, the v-model solution is only suited to one input returning to their parent. I took a bit of time looking for it but Vue (2.3.0) documentation does show how to sync multiple props sent into the component back to the parent (via emit of course).
It is appropriately called the .sync modifier.
Here is what the documentation says:
In some cases, we may need “two-way binding” for a prop.
Unfortunately, true two-way binding can create maintenance issues,
because child components can mutate the parent without the source of
that mutation being obvious in both the parent and the child.
That’s why instead, we recommend emitting events in the pattern of
update:myPropName. For example, in a hypothetical component with a
title prop, we could communicate the intent of assigning a new value
with:
this.$emit('update:title', newTitle)
Then the parent can listen to
that event and update a local data property, if it wants to. For
example:
<text-document
v-bind:title="doc.title"
v-on:update:title="doc.title = $event"
></text-document>
For convenience, we offer a shorthand for this pattern with the .sync modifier:
<text-document v-bind:title.sync="doc.title"></text-document>
You can also sync multiple at a time by sending through an object. Check out the documentation here
The way more simple is use this.$emit
Father.vue
<template>
<div>
<h1>{{ message }}</h1>
<child v-on:listenerChild="listenerChild"/>
</div>
</template>
<script>
import Child from "./Child";
export default {
name: "Father",
data() {
return {
message: "Where are you, my Child?"
};
},
components: {
Child
},
methods: {
listenerChild(reply) {
this.message = reply;
}
}
};
</script>
Child.vue
<template>
<div>
<button #click="replyDaddy">Reply Daddy</button>
</div>
</template>
<script>
export default {
name: "Child",
methods: {
replyDaddy() {
this.$emit("listenerChild", "I'm here my Daddy!");
}
}
};
</script>
My full example: https://codesandbox.io/s/update-parent-property-ufj4b
It is also possible to pass props as Object or Array. In this case data will be two-way binded:
(This is noted at the end of topic: https://v2.vuejs.org/v2/guide/components.html#One-Way-Data-Flow )
Vue.component('child', {
template: '#child',
props: {post: Object},
methods: {
updateValue: function () {
this.$emit('changed');
}
}
});
new Vue({
el: '#app',
data: {
post: {msg: 'hello'},
changed: false
},
methods: {
saveChanges() {
this.changed = true;
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.js"></script>
<div id="app">
<p>Parent value: {{post.msg}}</p>
<p v-if="changed == true">Parent msg: Data been changed - received signal from child!</p>
<child :post="post" v-on:changed="saveChanges"></child>
</div>
<template id="child">
<input type="text" v-model="post.msg" v-on:input="updateValue()">
</template>
In Parent Conponent -->
data : function(){
return {
siteEntered : false,
};
},
In Child Component -->
this.$parent.$data.siteEntered = true;
2021 ANSWER - Vue 2.3+
SHORT ANSWER: Just add .sync modifier in the parent and pass the data as props to the children:
// PARENT:
data () {
return {
formData: {
members: [] //<- we wanna pass this one down to children and add/remove from the child component
}
}
// PARENT TEMPLATE:
<!-- ADD MEMBERS -->
<add-members :members.sync="formData.members" />
Nested child component: AddMembers.vue
export default {
name: 'AddMembers',
props: ['members'],
methods: {
addMember () {
this.members.push(new Member()) // <-- you can play and reactivity will work (in the parent)
},
removeMember (index) {
console.log('remove', index, this.members.length < 1)
this.members.splice(index, 1)
}
}
}
Long story: changes from the child component in reallity are being $emitted and updating formData.members[] of the parent.
source: Mauro Perez at medium
In the child
<input
type="number"
class="form-control"
id="phoneNumber"
placeholder
v-model="contact_number"
v-on:input="(event) => this.$emit('phoneNumber', event.target.value)"
/>
data(){
return {
contact_number : this.contact_number_props
}
},
props : ['contact_number_props']
In parent
<contact-component v-on:phoneNumber="eventPhoneNumber" :contact_number_props="contact_number"></contact-component>
methods : {
eventPhoneNumber (value) {
this.contact_number = value
}
The correct way is to $emit() an event in the child component that the main Vue instance listens for.
// Child.js
Vue.component('child', {
methods: {
notifyParent: function() {
this.$emit('my-event', 42);
}
}
});
// Parent.js
Vue.component('parent', {
template: '<child v-on:my-event="onEvent($event)"></child>',
methods: {
onEvent: function(ev) {
v; // 42
}
}
});
When we want to pass the data to the parent component as well as another nested child component of the current child component, using a data property would be useful as shown in the following example.
Example:
Calling your child component from the parent component like this.
Parent component:
<template>
<TodoItem :todoParent="todo" />
</template>
<script>
export default {
data() {
return {
todo: {
id:1,
task:'todo 1',
completed:false
}
};
}
}
</script>
Child component:
<template>
<div class="todo-item" v-bind:class="{'is-completed':todo.completed}">
<p>
<input type="checkbox" #change="markCompleted" />
{{todo.task}}
<button class="del">x</button>
</p>
</div>
</template>
<script>
export default {
name: "TodoItem",
props: ["todoParent"],
data() {
return {
todo: this.todoParent,
};
},
methods: {
markCompleted() {
this.todo.completed = true
},
},
};
</script>
Even you can pass this property to the nested child component and it won't give this error/warning.
Other use cases when you only need this property sync between parent and child component. It can be achieved using the sync modifier from Vue. v-model can also be useful. Many other examples are available in this question thread.
Example2: using component events.
We can emit the event from the child component as below.
Parent component:
<template>
<TodoItem :todo="todo" #markCompletedParent="markCompleted" />
</template>
<script>
export default {
data() {
return {
todo: {
id:1,
task:'todo 1',
completed:false
}
};
},
methods: {
markCompleted() {
this.todo.completed = true
},
}
}
</script>
Child component:
<template>
<div class="todo-item" v-bind:class="{'is-completed':todo.completed}">
<p>
<input type="checkbox" #change="markCompleted" />
{{todo.task}}
<button class="del">x</button>
</p>
</div>
</template>
<script>
export default {
name: "TodoItem",
props: ["todo"],
methods: {
markCompleted() {
this.$emit('markCompletedParent', true)
},
}
};
</script>
Another way is to pass a reference of your setter from the parent as a prop to the child component, similar to how they do it in React.
Say, you have a method updateValue on the parent to update the value, you could instantiate the child component like so: <child :updateValue="updateValue"></child>. Then on the child you will have a corresponding prop: props: {updateValue: Function}, and in the template call the method when the input changes: <input #input="updateValue($event.target.value)">.
I don't know why, but I just successfully updated parent data with using data as object, :set & computed
Parent.vue
<!-- check inventory status - component -->
<CheckInventory :inventory="inventory"></CheckInventory>
data() {
return {
inventory: {
status: null
},
}
},
Child.vue
<div :set="checkInventory">
props: ['inventory'],
computed: {
checkInventory() {
this.inventory.status = "Out of stock";
return this.inventory.status;
},
}
his example will tell you how to pass input value to parent on submit button.
First define eventBus as new Vue.
//main.js
import Vue from 'vue';
export const eventBus = new Vue();
Pass your input value via Emit.
//Sender Page
import { eventBus } from "../main";
methods: {
//passing data via eventbus
resetSegmentbtn: function(InputValue) {
eventBus.$emit("resetAllSegment", InputValue);
}
}
//Receiver Page
import { eventBus } from "../main";
created() {
eventBus.$on("resetAllSegment", data => {
console.log(data);//fetching data
});
}
I think this will do the trick:
#change="$emit(variable)"
Intro
I was looking for sending data from parent to child (and back) in vue3 (I know the question was about vue2, but there are no references for vue3 on SO at the time).
Below is the working boilerplate result, pure "html + js", no packagers, modules, etc with few caveats I had, explained.
Notes:
Tnserting the child - line
<component-a :foo="bar" #newfooevent="bar = $event"></component-a>`
I bind parent.bar to child.foo using short-hand :foo="bar", same as v-bind:foo="bar". It passes data from parent to child through props.
Caveat: Event listener should be placed in the child component tag only!
That is the #newfooevent="bar = $event" part.
You cannot catch the signal in the <div id="app"> or anywhere else inside the parent.
Still, this is the parent's side of the universe, and here you can access all parent's data and extract the data from the child's signal to deal with it.
You can create app, and define component after it (the app.component("component-a", ...) part.
Caveat: there are no need in forward declaration of components, e.g. functions in C/C++. You can create app which uses the component, and define the component afterwards. I lost a lot of time looking for the way to declare it somehow - no need.
Here you can find a nice example of the v-model usage, and the code I used to sort things out: https://javascript.plainenglish.io/vue-3-custom-events-d2f310fe34c9
The example
<!DOCTYPE html>
<html lang="en">
<head>
<title>App</title>
<meta charset="utf-8" />
<script src="https://unpkg.com/vue#next"></script>
</head>
<body>
<div id="app">
<component-a :foo="bar" #newfooevent="bar = $event"></component-a>
<p>Parent copy of `bar`: {{ bar }}</p>
<button #click="bar=''">Clear</button>
</div>
<script>
const app = Vue.createApp({
data() {
return {
bar: "bar start value"
};
}
});
app.component("component-a", {
props: {
foo: String
},
template: `
<input
type="text"
:value="foo"
#input="$emit('newfooevent', $event.target.value)">
`
});
app.mount("#app");
</script>
</body>
</html>
There is another way of communicating data change from child to parent which uses provide-inject method. Parent component "provides" data or method for the child component, and this data or method is then "injected" into child component - but it can also be used for triggering a method in parent and passing it a parameter.
This approach can be especially useful when having a child component which happens to be embedded in multiple other components. Also, in a large project care must be taken not to lose overview of provide and inject usage.
Example of parent (top level) component App.vue using provide to give access to it's method updateParentValue (if method is provided and not data, provide is in form of a method):
<template>
<h2>App.vue, parentValue is: <em>{{ parentValue }}</em></h2>
<ChildComponent1 />
</template>
<script>
import ChildComponent1 from "./components/ChildComponent1.vue";
export default {
data() {
return {
parentValue: "",
};
},
components: {
ChildComponent1,
},
provide() {
return {
updateParent: this.updateParentValue,
};
},
methods: {
updateParentValue($value) {
this.parentValue = $value;
},
},
};
</script>
In this example component Component4.vue is in the "bottom", that is, App.vue contains Component1, Component1 contains Component2... until Component4 which actually utilizes inject to get access to parent method which is then invoked and a parameter $value is passed (just a random number here):
<template>
<div>
<h2>ChildComponent4.vue</h2>
<button #click="updateParent(Math.random())">
Update parent value in App.vue
</button>
</div>
</template>
<script>
export default {
inject: ["updateParent"],
};
</script>
Entire example is available here.
Vue.js documentation

Categories

Resources