I have 3 vue.js nested components: main, parent, child.
The parent component load basic data, the child is a simple countdown widget which needs just a data to be configured.
If I set the parent script with static data (IE deadline='2019-12-12') the child show the widget working nice, but if I use dynamic data it generate error.
I'm using computed to pass data to the child component and if I debug it using an alert I see 2 alerts: undefined and then the correct date.
The issue is the first computed data (undefined) crash the widget, so how to create child component using updated (loaded) data?
Parent template:
<template>
<div>
<flip-countdown :deadline=deadline></flip-countdown>
</div>
</template>
Parent Script: it needs to be fixed
export default {
components: {FlipCountdown},
props: ['event'],
computed: {
deadline: function () {
if (typeof(this.event.date)!="undefined") {
//alert(this.event.date)
return this.event.date;
} else {
return "2019-05-21 00:00:00";
}
},
},
Child template: it works
<template>
<div>
<flip-countdown :deadline="deadline"></flip-countdown>
</div>
</template>
Your parent component passes the deadline to its child component before the mounted lifecycle hook fires. Your child component sets its deadline with the initial value of undefined.
You should make deadline a computed property in child component:
computed: {
internalDeadline() {
return this.deadline; // comming from props
}
}
Then you can use internalDeadline in child.
Alternatively, you could wait to render the child component until deadline is defined:
<flip-countdown v-if="deadline !== undefined" :deadline="deadline"></flip-countdown>
Related
I have included an $emit in an axios post of a child component as follows.
axios.post('/api/register', qdata)
.then((response) => {
this.$emit('userUpdated', response.data)
})
In the parent component, I have a div element in the html code containing a v-on, which refers to the userUpdated of the $emit.
<div id="username" v-on:userUpdated="nameUpddated($event)">
<p>{{userid}}</p>
</div>
Finally, the script section of the parent contains the following function called by the v-on.
nameUpddated: function (updatedUser) {
this.userid = updatedUser
}
I have validated that the axios returns a proper value in the Child component. However, the function in the parent never gets called.
In your parent component use child component name instead of div.
Edit: I also added v-if to conditionally show the component.
<child-component v-if="isVisible" id="username" v-on:userUpdated="nameUpddated($event)">
<p>{{userid}}</p>
</child-component>
Also, you need to add a data property to show the component conditionally (initially hidden).
data () {
return {
isVisible: false
}
}
Now, it is up to you at what point you want to show the child component. You would simply change isVisible to true.
After making this change, it should work as expected.
Note: please remember to register the child component properly as well in your parent component:
import childComponent from '#/components/childComponent'
export default {
components: {
childComponent
}
}
I have parent and chidl component... I need to run child method, when i click on button in parent.
Example code:
Parent
<template>
<child-component></child-component>
<button>Open Modal in child Component (set modal = true in child component)</button>
</template>
Child:
<template>
<div v-if="modal">
<button #click="modal = false">Close</button>
</div>
</template>
<script>
export default {
data() {
return {
modal: false
}
}
}
</script>
You can achieve this via different implementations. The most common one is via emit (another alternative is via dispatching actions if you are using the Redux pattern)
First, you want to catch the even on the parent component and emit an event. So this should be your template.
<template>
<child-component></child-component>
<button #click="click">Open Modal in child Component (set modal = true in child component)</button>
</template>
Then you have to emit an event (from the parent component) on the function called when a click was made.
Something like:
click: function() {
this.$emit('update');
}
Lastly, your child component needs to "hear" that event. You can achieve that with something like that on the created function of the child component:
this.$parent.$on('update', this.updateModal);
this.updateModal is a function on your child component which just flips the value of the boolean.
In vue you can pass a function as a prop. So you could add a function to alternate model within your parent component then pass it into your child so it can be used normally. I'll put a simple example below.
small edit, you can bind a class like a hidden/reveal class using the status which is bound to the modal state
// Html
<div id="app">
<child v-bind:on-click="toggleModal" v-bind:status="modal" />
</div>
// Parent Component
var sample = new Vue({
el: '#app',
data: {
modal: false
},
methods: {
toggleModal() {
this.modal = !this.modal
}
}
});
// Child component with function prop
Vue.component('child', {
props: {
onClick: Function,
status: Boolean
}
template: '<button v-on:click="onClick()">Press Me</div>'
});
I want to pass down the changes made in parent component data values to its child components each time the value changes in parent how can i achieve it in vue.js. I am using 3 custom components that have to reflect the current value of the parent component each time. p.s i am new to vue.js
you just need to pass it as a prop. In your template:
<my-component :my-prop="myData" />
and in your script tag:
export default {
data() {
myData: 0,
}
}
Whenever you update this.data, the component will update its view, as the prop will have changed
Data is typically passed one-way from parent to child components via props. See the documentation on this here.
Example:
// register the child component
Vue.component('child', {
props: ['myProp'],
template: '<span>{{ myProp }}</span>'
})
// in parent component
<child :my-prop="hello"></child>
This is an easy question but I dont know the best way to do it correctly with Vue2:
Parent Component:
<template>
<div class="parent">
<child></child>
{{value}} //How to get it
</div>
</template>
Child Component:
<template>
<div class="child">
<p>This {{value}} is 123</p>
</div>
</template>
<script>
export default {
data: function () {
return { value: 123 }
}
}
</script>
Some ways you can achieve this include:
You can access the child VM directly via a ref, but this gets hairy because the ref won't be populated until the child component has mounted, and $refs isn't reactive, meaning you'd have to do something hacky like this:
<template>
<div class="parent">
<child ref="child"></child>
<template v-if="mounted">{{ $refs.child.value }}</template>
</div>
</template>
data() {
return {
mounted: false
}
},
mounted() {
this.mounted = true;
}
$emit the value from within the child component so that the parent can obtain the value when it is ready or whenever it changes.
Use Vuex (or similar principles) to share state across components.
Redesign the components so that the data you want is owned by the parent component and is passed down to the child via a prop binding.
(Advanced) Use portal-vue plugin when you want to have fragments of a component's template to exist elsewhere in the DOM.
Child components pass data back up the hierarchy by emitting events.
For example, in the parent, listen for an event and add the child value to a local one (an array for multiple child elements would be prudent), eg
<child #ready="childVal => { value.push(childVal) }"></child>
and in the child component, $emit the event on creation / mounting, eg
mounted () {
this.$emit('ready', this.value)
}
Demo ~ https://jsfiddle.net/p2jojsrn/
Thanks for reading my question.
I have doubts about how to accomplish this in my Vue.js app.
Parent Component: App.vue
Child Components: Loading.vue, ProductsList.vue, NoProductList.vue
The App component is the container. When the page loads, the Loading component is displayed.
The Loading component then checks for products. If there are products the Loading component will return the products as an object.
If there aren't any products the Loading component will return null.
How do I tell the App component which component to use based on the Loading components return value? ie.. Load the ProductsList component if there are products and the NoProduct component when there aren't any products?.
What's the correct way to do notify the parent component about which component it should use in Vue?
Should I use $emit (pass data from child to parent), State Management https://v2.vuejs.org/v2/guide/state-management.html#Simple-State-Management-from-Scratch or a Bus component?
Some code...
Loading.vue component (child):
export default {
name: 'loading',
data () {
return {
message: ''
}
},
mounted: function () {
this.loadingProcess();
},
methods: {
loadingProcess: function () {
//process
this.$emit('found-products', 'hola');
}
}
App.vue component (parent):
<template>
<div>
<div id="resultComponent" #found-products="checkProductsList">
<loading></loading>
...
</div>
</div>
</template>
Thanks in advance.
For parent-child interactions, the correct way is for the child to $emit and the parent to set props.
State management and buses are for more complex systems where data must be shared by not-closely-related components.