$refs between parent and child component - vue.js

How to access component via ref from parent component, if targeted component is created in child/grandchild... components?
Example:
Parent component is supposed to get/set data to children via ref.
<child>
...
</child>
<script>
...
methods:{
getSomeGrandChildViaRef(){
stuffComponent = this.$refs['id_1']
// only accessible this way if component is registered within this (parent component)
}
}
...
Inside Child component:
<template>
...
<stuff
ref="id_1"
/>
<template>
Using props or store for this solution is possible but I would perfer to avoid it.
This approach of "injecting" data directly is more appropriate for this case.
Any ideas?

Related

How to use v-if on a child component to be reactive to the parents attributes?

I have a Child component, which displays a warning message if the wrong dates from an Input are selected. This warning should only be possible in the Parent Component, because the Child is re-used throughout my application.
I want to add a v-if to the warning notification, that it can only appear if it's rendered in that exact Parent Component, and not anywhere else the component is re-used.
I have tried with V-If, tied to the component name , but that has not solved the issue.
What is the best way to make the child component register that it has been rendered in ParentComponent?
<ChildComponent>
<div>
<b-datepicker
class="datepicker-input"
/>
<b-notification
v-if="this.componentName === 'parentComponent" >
'WARNING, WRONG DATES SELECTED'
</b-notification>
</div>
<ParentComponent>
<div>
<ChildComponent>
</ChildComponent>
</div>
data() {
return {
componentName: this.$options.name,
</ParentComponent>

Passing data from template to component

I have the following, which for my understanding should pass the value of html attribute to the #Prop with the same name however my console.log is always undefined. How is this accomplished?
import Vue from 'vue';
import { Component, Prop } from 'vue-property-decorator';
#Component({})
export default class RelayComponent extends Vue {
#Prop([String]) service: string;
constructor() {
super();
console.log(this.service);
...
HTML
<template>
<div service="expecting this value passed"></div>
</template>
<script src="./relay.ts"></script>
Vue props
Vue props are intended to pass data from a parent vue component or instance to a child vue component.
So you have a vue component, you set up a #Prop and then you get the prop for the html of the parent. Should you have a my-parent and my-child components, the my-parent template could be:
<template>
<my-child count="7"></my-child>
</template>
So a child component like this:
<template>
<div class="counter">{{count}}</div>
</template>
<script lang="ts">
import Vue from 'vue';
import { Component, Prop } from 'vue-property-decorator';
#Component({})
export default class myChild extends Vue {
#Prop() count: number;
}
</script>
Would get 7 as its count prop.
Now, in your case, there is only one component, and you're trying to setup the service variable of the component from the HTML. This is sort of weird because the point of Vue is to achieve declarative rendering from the component data: is the HTML who reacts to data changes, not your component who gets data from the HTML.
(Of course, you can also setup v-model and event listeners to make your components react to user input, but that's another story).
Basically, if I understood correctly what you want to do, your issue is that you're trying to get the service prop from the HTML of the very RelayComponent component.
Instead, you should setup the service prop in the component parent:
// Code of some parent component that renders the RelayComponent
<template>
<relay-component service="this would set the service prop as a string"></relay-component>
</template>
Only, when dealing with objects, you usually don't pass down a plain string, but a javascript object, and a service variable probably is an object, so changes are you're behind something like this:
<template>
<relay-component v-bind:service="serviceVariableInTheParentComponent"></relay-component>
</template>
Where the parent component has a service variable in its data.
 Constructor and lifehooks
Be wary about explicitly calling constructor in vue class components. If you modify the component state in the constructor, you can break the component.
Probably, you should consider to ever use the created() lifecycle hook instead of constructor() in every Vue component.

Pass change to child components when data value in parent component is changed in vuejs

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>

How to get child component's data in VueJs?

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/

Pass information from a child component to a parent component with Vue.js

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.