How can I access the value of a nested vue.js component? - vue.js

I have a component called lbcontainer and a second component called lbitem.
Now I want to nest any number of lbitem components into one lbcontainer component.
The lbcontainer component has a method that should access all lbitem components that I have nested in the lbcontainer component.
Problem is: with ref I can get to the item via this.$ref.lbitem, but this only works in the component declaration, but not when I use the component later in HTML.
Vue.component('lbcontainer', {
methods: {
"showChildren": function() {
console.log(this.$refs);
}
},
template: `
<div>
<slot></slot>
<a #click='showChildren'>Show children</a>
</div>
`
});
Vue.component('lbitem', {
data: function() {
return {
value: ""
}
},
template: `
<input v-model="value"></span>
`
});
new Vue({
el: "#app",
data: {
},
methods: {
}
});
<div id="app">
<lbcontainer>
<lbitem ref="item"></lbitem>
<lbitem ref="item"></lbitem>
</lbcontainer>
</div>
When I press the button the console.log shows an empty object. How can I access the nested children?
Here is jsfiddle

Avoiding using $ref in vue ...
( $ref is populated after the first render...)
child can only communicate with their parent by event ...
or parent have all data and send to their child by props.
if parent and chidrend have to edit the data you can use v-model or .sync;
https://codesandbox.io/s/p95x1mxykm

Related

How to call a component method each time this component show in vue2?

Vue component hasn't onShow lifecycle method.
How to call a component method each time this component show in vue2?
I have used this library for that purpose before:
https://github.com/Akryum/vue-observe-visibility
I am assuming you are dynamically hiding and showing the component and you want to trigger few functionality every time component show. If Yes, You can simply achieve this requirement by using v-if directive instead of v-show. As v-if will rebuild the component every time condition got passed.
Live Demo :
Vue.component('child', {
props: ['childmsg'],
template: '<p>{{ childmsg }}</p>',
mounted() {
console.log('child component mounted');
}
});
var app = new Vue({
el: '#app',
data: {
buttonMsg: 'Show Child Component',
showChild: false
},
methods: {
toggleBtn() {
this.showChild = !this.showChild;
this.buttonMsg = this.showChild ? 'Hide Child Component' : 'Show Child Component';
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<button #click="toggleBtn">{{ buttonMsg }}</button>
<child v-if="showChild" childmsg="This is a child message"/>
</div>

How to check if child component is mounted in vue?

I want to check if child component is mounted and I want to move that information to he parent component. For this I am using emits.
So with example here is my parent component:
<child #is-child-mounted="childMounted" />
export default {
data() {
return {
childMounted: false,
};
},
mounted() {
if (this.childMounted) {
//do something
}
},
}
and in child component, I am changing 'is-child-mounted' to true:
mounted() {
this.$emit('isChildMounted', true);
},
But still if (this.childMounted) comes false. So how can I check in parent component if the child component is mounted?
You can add a listener on the child component fom the parent. It would look like this:
Vue3
<Component
#vnodeMounted="handleMounted"
/>
Vue2
<Component
#hook:mounted="handleMounted"
/>
You can replace the hook name by the lifecycle one you want to listen to ! I guess it should be used sparsely as it is not present in the documentation and thus be an internal API that is not destined to be used directly.
source:
https://github.com/vuejs/core/issues/4345#issuecomment-899082892
https://github.com/vuejs/vue/blob/8d3fce029f20a73d5d0b1ff10cbf6fa73c989e62/src/core/instance/lifecycle.js#L348
Looks like there is a typo in the event name in the child component while triggering the event else code should work fine.
It should be is-child-mounted instead of ischildmounted
It should be #is-child-mounted="childMounted = true" instead of #is-child-mounted="childMounted"
Live Demo :
Vue.component('child', {
props: ['childmsg'],
template: '<p>{{ childmsg }}</p>',
mounted() {
this.$emit('is-child-mounted')
}
});
var app = new Vue({
el: '#app',
data: {
childMounted: false
},
mounted() {
if (this.childMounted) {
console.log('child mounted');
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<child childmsg="This is a child component" #is-child-mounted="childMounted = true"></child>
</div>

Vue stored valued through props not being reactive

So I pass value using [props] and stored it in child component's data. However, when passing [props] value changes from parent, it's not updating in child component's data. Is there a fix for this..?
Here is the link to w3 test (I tried to clarify the problem as much as possible here)
<div id='app'>
<div id='parent'>
<button #click='current_value()'>Click to see parent value</button>
<br><br>
<button #click='change_value($event)'>{{ txt }}</button>
<br><br>
<child-comp :test-prop='passing_data'></child-comp>
</div>
<br><br>
<center><code>As you can see, this methods is <b>NOT</b> reactive!</code></center>
</div>
<script>
new Vue({
el: "#parent",
data: {
passing_data: 'Value',
txt: 'Click to change value'
},
methods: {
current_value(){
alert(this.passing_data);
},
change_value(e){
this.passing_data = 'New Vaule!!';
this.txt = 'Now click above button again to see new value';
e.target.style.backgroundColor = 'red';
e.target.style.color = 'white';
}
},
components: {
"child-comp": {
template: `
<button #click='test()'>Click here to see child (stored) value</button>
`,
props: ['test-prop'],
data(){
return {
stored_data: this.testProp
}
},
methods: {
test(){
alert(this.stored_data);
}
},
watch: {
stored_data(){
this.stored_data = this.testProp;
}
}
}
}
});
Props have one way data flow, that's why it doesn't react when you update it from the parent component. Define a clone of your prop at data to make it reactive, and then you can change the value within the child component.
Short answer: you don't need stored_data. Use alert(this.testProp) directly.
Long answer: when child component is created, stored_data get it's value from this.testProp. But data is local, it won't change automatically. That's why you need to watch testProp and set it again. But is not working because of a simple mistake, your watch should be:
watch: {
testProp(){ // here was the mistake
this.stored_data = this.testProp;
}
}

How i can run method from child component vuejs

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>'
});

Change value of a props in beforeDestroy/Destroyed cycle of child component does not work

Hi I made a boolean value in parent component, and passed it to the child component as a props. it has initialized as false, and after the user view the component, the value will change to true, which means the page has been visited.
I have done some research and followed How to properly pass data from child to parent and parent to child component?
here is my js code:
<script>
export default {
props: {
hasLoad: {
type: Boolean
}
},
data () {
return {
hasLoadModel: this.hasLoad
}
},
created: function() {
console.log(this.hasLoad);
},
beforeDestroy: function() {
this.hasLoadModel = true;
this.hasLoad = true;
console.log(this.hasLoadModel);
console.log(this.hasLoad);
}
}
</script>
and html code
<div v-model="skillLoadModel">..</div>
But I still get
[Vue warn]: Avoid mutating a prop directly since the value will be
overwritten whenever the parent component re-renders. Instead, use a
data or computed property based on the prop's value.
I have tried to change the value at either of beforeDestroy or Destroyed, or do not use v-model, but none of them works. The value has changed after I left the page, but when I reenter the page, the value has reset to default value.
Can someone help me please?
Thanks
Don't change the value of the prop. Have the component emit an event so that the parent can take the appropriate action.
Below is an example of a component that is created when the checkbox is checked, and is destroyed when it gets unchecked. The component emits a "dying" event, and the parent receives it and prints a scream to the console.
new Vue({
el: '#app',
data: {
showIt: true
},
methods: {
scream() {
console.log("Aaarg!");
}
},
components: {
myComponent: {
beforeDestroy: function() {
this.$emit('dying');
}
}
}
});
<script src="//unpkg.com/vue#latest/dist/vue.js"></script>
<div id="app">
<input type="checkbox" v-model="showIt">
<my-component v-if="showIt" hasload="true" #dying="scream" inline-template>
<div>Here I am</div>
</my-component>
</div>
I assume you're trying to communicate to the parent that the child has loaded. In that case, you can pass a function as a prop and simply call it when the child mounts.
Parent HTML:
<child :my-load-fn="loadFn"></child>
Parent JS:
methods: {
loadFn() {
this.childHasLoaded = true
}
}
Child JS:
props: ['myLoadFn'],
mounted() {
this.myLoadFn()
}