Vue.js Passing variable from Parent to child component - javascript

Parent component: ShowComment
Child component: EditComment
I'm trying to pass the value of this.CommentRecID to the child component.
I wrote this in the template of ShowComment:
<EditComment CommentRecID="this.CommentRecID" v-if="showEdit"></EditComment>
and
this.showEdit = true;
but the value of this.CommentRecID is shown as undefined in the child component:
I thought that writing props: ["CommentRecID"], in the child component would have already been enough to pass the data, but it wasn't (because it's related to jQuery I think).
What is wrong with the way I try to pass the values?
Here's the parent component.
Here's the child component.

You shouldn't need to use this in VueJS directives. Also, instead of using a static attribute, you need to use v-bind:
<EditComment v-bind:comment-rec-id="commentRecId" v-if="showEdit"></EditComment>
Also, there's an issue with the casing: for VueJS, in template props should be kebab-cased, while in the component JS logic you should use camelCase props. Remember to update your child component's prop declaration so that it can read the new prop correctly:
props: ["commentRecId"]

You need to use VueJS binding
<EditComment :comment-rec-id="CommentRecID" v-if="showEdit"></EditComment>
props: ['commentRecId']

Related

Vue how to access props of parent component - the importer not a wrapper

Overall goal: from a child Vue component, get access to the component that it is imported and used within - which is not always the same as $parent. This should be done by only making changes within the child component (if possible).
We have PinButton Vue component meant to add a "pinning" functionality to other components. This component is used within many other components and we want to be able to access the parent props so they can be saved and rendered on a different page of "pinned content" by passing those props back into the parent component.
Note: I know this would be possible by manually passing the parent props down into the component (<pin-button :parent-props="$props" />), but we're trying to avoid having to do this every time the component is used.
A minimal reproduction of this with a single parent and child component will show that you can access parent props using $parent.$props. However, when the child component is nested as slot content of some other component within the parent, then the child will get the props of the wrapper component - not the component in which it is imported and actually used.
Sandbox reproduction - I want to get the props for ParentComponent from within ChildComponent. The expected value is shown by passing the props along (what I'm trying to avoid) and the actual value is the props of the SlotWrapper component, which doesn't import ChildComponent so I wouldn't consider it the true parent, but it is the direct parent element in the <template>
Update:
Seems like the suggested solution for "arbitrarily deep" access is provide/inject, but this would still seem to require changing all components that use the <pin-button />
To answer your question directly, you can access ParentComponent from ChildComponent via the "context" the component is rendered within:
// ChildComponent.vue
computed: {
expectedProps() {
return this.$vnode.context.$props
}
}
But this might be an "XY" kind of problem; I'm sure there's a better design solution for what you're trying to achieve.

How to use ref on <component> in vuejs?

I am having two independent VUE components and I want to communicate between them.
In the first component, I am using <component> and added ref to it.
<component ref="dynamicComponent"></component>
and in that above dynamic component, there is a method(suppose dynamicMethod) and I want to call that method from second component.
So for that, I am using below code:
this.$root.$refs.dynamicComponent.dynamicMethod();
But I am getting this.$root.$refs a blank object. How can I call that method.
Any help would be appreciated.
Make sure you're trying to access $refs only after the component is mounted.
You should be able to access the $refs in the mounted hook.
mounted: function() {
console.log(this.$refs);
},

How can i get boolean data from another component in vue js?

I have two Components.
In the second component, "date-detail-filter" I always keep track for boolean value, and want to access this data in my parent component.
do you know how to use $emit?
In your date-detail-filter component
you can add this to your method. this.$emit('your-event-name', 'your payload')
and in your main component.
<date-detail-filter #your-event-name="functionName()"/>
functionName(payload) {
your logic here to hide the caret
}
$emit is used to pass data from child component to parent component via event.

Cannot pass parent component's object as prop in Vue after Laravel Mix update

I recently updated laravel mix in my project to the latest and immediately I was swarmed by Vue errors. I seem to struggle with this one especially. I have a component:
<template>
<div>
<ChildComponent :context="this"></ChildComponent>
</div>
</template>
<script>
import ChildComponent from './child-component';
export default {
components: { ChildComponent },
...
}
</script>
This is the error I get: Error in render: "TypeError: Cannot read property 'context' of undefined".
Seems weird because in vue-devtools the parent component is present as an object in context prop of ChildComponent.
I should probably also add that context is defined as context: {} in ChildComponent's props.
this is not defined in the <template> and attempting to pass the entire Vue instance to the child seems like an anti-pattern. You should explicitly define and pass data and variables to children components, and (optionally) if you want to receive some data back from the child, you should emit events and bind to those events in the parent.
If you must access the parent component from the child, you can use this.$parent in the child component: https://v2.vuejs.org/v2/guide/components-edge-cases.html#Accessing-the-Parent-Component-Instance
But unless you have a good reason to reach for that $parent variable, it should be avoided as it tightly couples your components together.

vue - $emit vs. reference for updating parent data

We need to use $emit to update the parent data in a vue component. This is what has been said everywhere, even vue documentation.
v-model and .sync both use $emit to update, so we count them $emit here
what I'm involved with is updating the parent data using reference type passing
If we send an object or array as prop to the child component and change it in the child component, changes will be made to the parent data directly.
There are components that we always use in a specific component and we are not going to use them anywhere else. In fact, these components are mostly used to make the app codes more readable and to lighten the components of the app.
passing reference type values as prop to children for directly change them from children is much easier than passing values then handle emitted event. especially when there are more nested components
code readability is even easier when we use reference type to update parent.
For example, suppose we have grand-parent, parent and child components. in parent component we have a field that change first property of grand-parent data and in child component we have another field that change second property of grand-parent data
If we want to implement this using $emit we have something like this : (we are not using .sync or v-model)
// grand-parent
<template>
<div>
<parent :fields="fields" #updateFields="fields = $event" >
</div>
</template>
<script>
import parent from "./parent"
export default {
components : {parent},
data(){
return {
fields : {
first : 'first-value',
second : 'second-value',
}
}
}
}
</script>
// parent
<template>
<div>
<input :value="fields.first" #input="updateFirstField" />
<child :fields="fields" #updateSecondField="updateSecondField" >
</div>
</template>
<script>
import child from "./child"
export default {
components : {child},
props : {
fields : Object,
},
methods : {
updateFirstField(event){
this.$emit('updateFields' , {...this.fields , first : event.target.value})
},
updateSecondField(value){
this.$emit('updateFields' , {...this.fields , second : value})
}
}
}
</script>
// child
<template>
<div>
<input :value="fields.first" #input="updateSecondField" />
</div>
</template>
<script>
export default {
props : {
fields : Object,
},
methods : {
updateFirstField(event){
this.$emit('updateSecondField' , event.target.value)
},
}
}
</script>
Yes, we can use .sync to make it easier or pass just field that we need to child. but this is basic example and if we have more fields and also we use all fields in all component this is the way we do this.
same thing using reference type will be like this :
// grand-parent
<template>
<div>
<parent :fields="fields" >
</div>
</template>
<script>
import parent from "./parent"
export default {
components : {parent},
data(){
return {
fields : {
first : 'first-value',
second : 'second-value',
}
}
}
}
</script>
// parent
<template>
<div>
<input v-model="fields.first" />
<child :fields="fields" >
</div>
</template>
<script>
import child from "./child"
export default {
components : {child},
props : {
fields : Object,
}
}
</script>
// child
<template>
<div>
<input v-model="fields.second" />
</div>
</template>
<script>
export default {
props : {
fields : Object,
}
}
</script>
as you see using reference type is much easier. even if there was more fields.
now my question :
should we use reference type for updating parent data or this is bad approach ?
even if we use a component always in the same parent again we should not use this method ?
what is the reason that we should not use reference type to update parent?
if we should not use reference type why vue pass same object to children and not clone them before passing ? (maybe for better performance ?)
The "always use $emit" rule isn't set in stone. There are pros and cons of either approach; you should do whatever makes your code easy to maintain and reason about.
For the situation you described, I think you have justified mutating the data directly.
When you have a single object with lots of properties and each property can be modified by a child component, then having the child component mutate each property itself is fine.
What would the alternative be? Emitting an event for each property update? Or emitting a single input event containing a copy of the object with a single property changed? That approach would result in lots of memory allocations (think of typing in a text field emitting a cloned object for each keypress). Having said that, though, some libraries are designed for this exact purpose and work pretty well (like Immutable.js).
For simple components that manage only small data like a textbox with a single string value, you should definitely use $emit. For more complex components with lots of data then sometimes it makes sense for the child component to share or own the data it is given. It becomes a part of the child component's contract that it will mutate the data in certain circumstances and in some particular way.
what is the reason that we should not use reference type to update parent?
The parent "owns" the data and it knows that nobody but itself will mutate it. No surprises.
The parent gets to decide whether or not to accept the mutation, and can even modify it on-the-fly.
You don't need a watcher to know when the data is changed.
The parent knows how the data is changed and what caused the change. Imagine there are multiple ways that the data can be mutated. The parent can easily know which mutation originated from a child component. If external code (i.e. inside a child component) can mutate the data at any time and for any reason, then it becomes much more difficult for the parent to know what caused the data to change (who changed it and why?).
if we should not use reference type why vue pass same object to children and not clone them before passing ? (maybe for better performance ?)
Well yes, for performance, but also many other reasons such as:
Cloning is non-trivial (Shallow? Deep? Should the prototype be copied too? Does it even make sense to clone the object? Is it a singleton?).
Cloning is expensive memory- and CPU-wise.
If it were cloned then doing what you describe here would be impossible. It would be silly to impose such a restrictive rule.
#Vue Detailed usage of $refs, $emit, $on:
$refs - parent component calls the methods of the child component. You can pass data.
$emit - child components call methods of the parent component and pass data.
$on - sibling components pass data to each other.

Categories

Resources