Vue parent component get response from child method - vue.js

I have a parent component and a child.
From parent i want to call a method in child component and wait the response. How can i do that?
I need the response for adding a condition in the parent method.
<!-- MY CHILD COMPONENT -->
<my-child-component ref="childform" />
// parent method
methods: {
callChildMethod() {
this.$refs.childform.onSubmit()
// if want to get the response and do something
if (response) {
//do something
}
},
}
//child method
methods: {
onSubmit() {
//do something
return false
},
}

Your problem could be solved using refs and it works as follows:
In parent component:
<parent #click="clickHandler">
<child ref="child" />
</parent>
In your parent script tag:
methods: {
async clickHandler(){
//call child component's method using reference given in parent component
await this.$refs.child.child_method_name();
// rest of your parent code here
}
}

Related

Trigger a function after modify select value in children component - VueJs

I'm using VueJs and i have this children component in my father component, i need to trigger a function in the parent component, when the change in the select of the child component is detected.
Children component:
watch: {
selectCoin() {
this.$emit("currencyType", this.selectCoin["title"]);
}
}
Children component in my Father Component:
<app-select-coin
#coin="body.value = $event"
#currencyType="body.currencyType = $event"
:data="body"
/>
I need to call this method when the child component responds to $emit for the parent component:
methods :{
myFunction() {
}
}
I managed to do it by adding the function in the "v-on" in #currencyType, and passing as parameter the values ​​i received from the children in "$emit".:
<app-select-coin
#coin="body.value = $event"
#currencyType="myFunction(body.currencyType = $event)"
:data="body"
/>
methods :{
myFunction(ct) {
}
}

Is there any way to check the status of props when passing data from parent to child component

I have been troubled by a question for a long time. Now I am using Vue.js to develop a web project. What I want to do is to pass data from parent to child component. However, the child component's main program would run only after the props data was received, due to the async data transmission mechanism. So I would like to know whether these are some ways to check the status of props data in the child component. Therefore I can make sure the subsequent task would run after the data was passed.
For example, a feasible solution is axios.requset({..}).then(res => {..}).
You can use the watchers in your child component. Consider the following parent component:
Vue.component('parent-comp', {
props: ['myProp'],
template: `
<div>
<child-comp my-prop={someAsyncProp} />
</div>
`,
data() {
return {
// Declare async value
someAsyncProp: null
};
},
mounted() {
// Some async computation
axios
.requset({ url: '/get-data' })
.then(res => {
// Set value asynchronously
this.someAsyncProp = res;
});
}
});
Your child component would use watchers to check if data is available:
Vue.component('child-comp', {
props: ['myProp'],
template: '<div></div>',
watch: {
// Watch the property myProp
myProp(newValue, oldValue) {
if (newValue !== null) {
// Do something with the props that are set asynchronously by parent
}
}
}
})

Vue – pass variable from child template to App.vue

I read up on passing variables from child to parent using $emit but I can't fully figure it out yet.
In App.vue I have a <header/> component for the page header containing a button which controls the mobile navigation's visibility. On click it changes its class:
<button #click="toggleMobileNavigation" :class="isOpen ? 'is-open' : 'is-closed'">
The <header/>'s js:
export default {
data() {
return {
isOpen: false,
};
},
methods: {
toggleMobileNavigation() {
if(!this.isOpen) {
this.isOpen = true;
} else {
this.isOpen = false;
}
this.$emit(this.isOpen)
}
}
}
The App.vue:
<Header />
<main id="main" tabindex="-1" class="main" :class="isOpen">
This obviously this doesn't work and I can't figure out what the right way is to catch the $emit.
Thanks for any tips!
I would say you are on the right track, this child needs to emit some event to alert its parent of an important change.
But instead of doing this in your Header component:
this.$emit(this.isOpen)
Supply an event name:
this.$emit('opened', this.isOpen)
// or:
if (this.isOpen) {
this.$emit('opened');
} else {
this.$emit('closed');
}
The way you catch this event in the parent component (App.vue) should be:
<Header #opened="handleOpenedEvent"> // will call method handleOpenedEvent
// alternatively:
<Header #opened="menuStatus = $event"> // $event contains data you supply as second argument to your this.$emit(name, ...) call
// #[eventname] is one way of doing it, v-on is the same:
<Header v-on:opened="handleEvent">

Vue how to get value from sub component

Here is my use case:
My main page have several sub-components that collect different input from user, finally I want to submit the whole page with all inputs collected. Therefore I want to retrieve the data from sub-component
One option is to use store, but my sub-components are super simple, just some forms, store seems too heavy...
Another option is that I can modify prop, although I know this is bad practice, but this approach looks just perfect....
Is it ok to modify prop if my logic is simple?(just collect inputs from user)Or I have to go for Vuex and store
Expanding on excellent answers from Ifaruki and Andres Foronda, another, related option is the use of the sync modifier on the child component's prop.
Suppose the child component has a prop named name. In the parent component, you can use the sync modifier like this:
<Child :name.sync="childName"></Child>
Then, in the child component, when the value of the name prop should be updated, don't update it directly. Instead, emit an event that follows the naming convention for sync-able props, which is update:nameOfProp. So in our example, the child component would do this:
this.$emit('update:name', newName);
The benefit of the sync modifier is that we don't have to write an event handler function in the parent component--Vue does that for us and updates the variable that is bound to the prop automatically.
You can read more details about the sync modifier in the official docs.
Retreiving data from sub component works with $emit here an exapmle:
//parent copmonent
<template>
<div>
<child #someEvent="someMethod"></child>
</div>
</template>
import child from "path/"
<script>
export default {
components: {
child
},
methods: {
someMethod(data){
console.log(data);
}
}
}
</script>
Child component
<template>
<div>
<button #click="sendEvent">send</button>
</div>
</template>
<script>
export default {
methods: {
sendEvent(){
this.$emit("someEvent", "working");
}
}
}
</script>
$emit takes 2 arguments. The first is the event name and the second one is the data that you send.
The parent just needs to listen with # for that event that being fired.
you can listen an event from child an update the parent data property
//parent component
<div>
<input-name #updateName="eventToUpdateName" /> <!--child component-->
</div>
...
data: () => ({ nameFromChild: '' )},
methods: {
eventToUpdateName(value) {
this.nameFromChild = value; // Update from child value emitted
}
}
...
And in the child component
// Child component
<input v-model="name" />
...
data: () => ({ name: '' }),
// watch for changes in the name property and emit an event, and pass the value to the parent
watch: { name() { this.$emit('updateName', this.name } }
...
Also, You can use a v-model directive and emit 'input' event from child.
//parent component
<div>
<input-name v-model="nameFromChild" /> <!--child component-->
</div>
...
data: () => ({ nameFromChild: '' )}
...
Now in the child component you can have
// Child component
<div>
<input v-model="name" />
</div>
data: () => ({ name: '' }),
props: { value: { type: String, default: '' },
created() { this.name = this.value }, // You can receive a default value
watch: { name() { this.$emit('input', this.name } }
...

Vuejs copy dynamic components methods

I am trying to make a visual representation of a component library. I am using dynamic <component>s to render each component. However, as I am populating the component with its slots, I am running into issues due to parent methods missing.
I want the components to be usable (demo) therefore I need to compensate for this.$parent not working.
<template>
<component v-bind:is="'s-' + comp.name" v-bind="props" ref="comp"> <!-- this is the corrent parent-->
<div v-if="comp.slots">
<div
v-for="(slot, i) in comp.slots"
v-bind:key="i"
v-bind:slot="slot.name"
>
<div v-if="slot.type == 'component'"> <!-- childs parent -->
<de-mo v-bind:comp="slot" /> <!-- this is the child calling a method on the parent -->
</div>
<div v-html="slot.value" v-else></div>
</div>
</div>
</component>
</template>
<script>
export default {
name: 'deMo',
computed: {
props() {
if (this.comp.props) {
return this.comp.props.reduce((a, r) => {
a[r.name] = r.value
return a
}, {})
}
}
},
props: {
comp: {
type: Object,
required: true
}
},
methods: this.$ref.comp.methods, //<-- this is an error
mounted(){
console.log(this.$ref.comp.methods)
}
},
</script>
<style></style>
1) Is there a way to copy the methods from the parent into this "demo" component via the ref attr
2) Alternatively, is there a better method to produce the same results?
Thanks
you can try to spread parent methods in a beforeCreate lifecycle as at this point your parent will be created and your component is going to register its all methods,
beforeCreate() {
this.$options.methods = { ...this.$parent.$options.methods };
},
however you can not access any refs in this as refs are only registered after mount of the component.
Note: Any library should use provide and inject to communicate with their component instead of referencing the parent component directly.
You can use an Event bus to communicate between components that aren't directly related to each other. Also, this is the recommended way of communication from child to parent in Vue.
bus.js
import Vue from 'vue'
export default new Vue()
demo.vue // child component that wants to call a method in the parent
import Bus from './bus.js'
export default {
mounted () {
// [1] child component will emit an event in the bus when it want to call a method of parent
Bus.$emit('invoke-parent-fn', 'param')
}
}
parent.vue // parent component where you want to render other components dynamically
import Bus from './bus.js'
export default {
methods: {
fn (param) {
console.log('// do something ' + param)
}
},
mounted () {
// [2] parent will be listening to the bus event, when child will emit an event, the handler passed in to the listener will be invoked
// [3] invoke the required method in the handler
Bus.$on('invoke-parent-fn', param => this.fn(param))
}
}