Get v-if expression/data as plain text in child component - vue.js

Hy there,
I try to create a custom Vue component which is shown based on v-if directive. I also want to change the directive data (modalStatus) value from inside the component.
<modal v-if="modalStatus"></modal>
To update the data from the component i use a method similar to this.
closeModal () {
this.$parent.modalStatus = false
}
The problem is that sometimes i don't know the name of the data model (modalStatus) , can be anything.
My question is how can i get the data/expression name as a plain text from the modal component ?
I'm planing to use something like this to update the modalStatus
this.$parent['anyName'] = false
Thanks and stay safe !
Later Edit. I know how to accomplish all of the above using props or v-model. I wonder if is possible using strictly v-if. Thanks!

There are several approaches to get to a method or property in the parent component from the child.
The 'Vue Way' is to emit a message telling the parent to close.
Send the name in as a property
Parent
<child modalName='modalStatus' />
Child
this.$parent[this.modalName]=false
Send in a method
Parent
<child :close='onClose' />
// component method
onClose(){
this.modalStatus=false
}
Child
this.close()
Emit a message
Parent
<child-component #close='modalStatus=false' />
// or call a method
<child-component #close='onClose' />
// component method
onClose(){
this.modalStatus=false
}
Child
this.$emit('close')

Related

Vue / feel confused about get props via this.$options.propData in beforeCreate

I'm writing Vue2, and feel confused about life cycle of Vue.
Please help me, thx. :)
1.
If there is a prop called count.
Why can't count be accessed via this.count in beforeCreate, but it can be accessed via this.$options.propsData.count in same hook?
2.
what's the difference between this.count and this.$options.propsData.count?
3.
What's the meaning of "after props resolution" of sentence below?
Called immediately when the instance is initialized, after props resolution, before processing other options such as data() or computed
I did below,
<!-- child component in parent component -->
<Card :count="33" :data="data"></Card>
<!-- beforeCreate hook of child component -->
beforeCreate(): void {
console.log(this.$options);
}
then get something like this picture.

Understanding when to use : , # and without any in vue

I have been going through an already existing code and trying to understand different parameters passed inside a tag.
<some-element
placeholder ="show first name"
:someElement = "true"
#error = "showErrorAlert"
>
so what exactly is the difference between these three parameters passed and when to pass them.
I am very new to vue so I am struggling a bit.
If any one needs any further information please let me know.
to communicate data between components in vuejs we have two concept: props and events.
vue props
vue custom events
read the two links above to learn about them from vue documentation but in short say we have a component structure like this:
<parent-component>
---- | <child-component>
data flow from parent to child is done with the help of props. that is when you're defining child-component you can set in its vue instance object that this component can accept some prop like this.
props: {
text: { type: String },
value: { type: Boolean },
}
then when you use this component in the parent one you can pass the defined props to the component like this:
<child-component text="some text" :value="false" />
notice the : notation is just a shorthand for v-bind:value="false", if you don't use this binding the false will be sent to the child component as a string. for any other value type you should use binding.
please read the docs to learn more about binding in vue
attribute binding
v-bind shorthand
now, the data flow from child to parent is done via events so in your child component you can emit an event for the parent one to listen to like this:
this.$emit('event-name', payload)
then in the parent component where you used child component you can listen to this event like this
<child-component #event-name="doSomethingFun($event)" />
where doSomethingFun() is a method in parent component and we are passing the payload sent from child component to this method with $event
notice # notation is shorthand for v-on like v-on:event-name="doSomethingFun($event)"
: is shorthand for v-bind: and this is used for dynamic rendering for the attributes such as src, href etc.
# is shorthand for v-on:click which is event handler for function calls.
You can read more Event handling shorthand syntax

How to open and close a modal within a child component using a prop, vuejs?

I currently have the following child component
<Edit
#fetchInfo="fetchInfo"
:agencyData="agency"
:dialogEdit.sync="dialogEdit"
></Edit>
Which basically contains a modal
initially it is false, so as not to show the modal:
data(){
return {
dialogEdit: false
}
}
by a method I do:
open(){
this.dialogEdit = true;
}
In my <Edit></Edit> component I have:
<el-dialog title="Editar" :visible.sync="dialogEdit" width="60%">
</el-dialog>
and received with prop:
props: ["dialogEdit"],
But then when closing the modal from the child component I receive an error
[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. Prop being
mutated: "dialogEdit"
First of all, apparently you are using Element UI.
But, as the error suggests, you are modifying dialogEdit directly. When closing the element ui modal by clicking the X, dialogEdit becomes false. You could solve this using computed property, like suggested for example in this answer.
Since you are using Element UI you also have another possibility to solve this. The dialog has the event before-close which is fired before the modal is closed. There you can emit the new boolean value for dialogEdit to the parent. So keep the :dialogEdit.sync="dialogEdit" in child tag and add the before-close to the dialog and a function to handle, where you emit the new false value:
<el-dialog title="Editar" :before-close="handleClose" ....>
JS:
methods: {
handleClose() {
this.$emit('update:dialogEdit', false);
}
},
If you have some button in your modal to close the modal, you can add the same function there:
<el-button type="primary" #click="handleClose">Close</el-button>
SANDBOX
quite hard to understand your question. you should elaborate more.
is all this in the same file? if in that case you no need to create a props as there's already dialogEdit in the data() section.
props value is never redefined so if this is the cases, just remove the props.
if that's not solved your problem please update your question with better explaination because i just see one file.

how to update the props in vue when the grandchild file has send the succeed PUT request

i have three vue.js file. where the parent file (parent.vue) contains data of profile:[]
the data of profile is send to child file (child.vue) using props methods.
the child.vue also has it's own child file (grandchild.vue) that has been pass with the profile data by using props.
grandchildren will send a put request to API to change some data in profile.
my question is. how can i make sure the props will update on every change made in the profile data.
information : (parent.vue = main file, child.vue = drawer(from ant design), grandchild = popover)
i need the child.vue to update the profile data after the grandchild succeed send a put request to the API.
is there any way or reference link so i could make the props update after a put request from grandchild.vue i have tried watch method but the problem is the user need to close the drawer (child.vue) first and re open the drawer to update the props. is there any way the props update without closing the drawer?
example of code :
parent.vue :
// structure
<child.vue
:profile="profile"
/>
child.vue & grandchild.vue :
//script
props : [profile],
profile can be used as {{profile.subsdata}} in html or this.profile.subsdata javascript
Use an emit. Tell the parent component to update via another GET request or just pass the data back directly.
Child Method:
notifyParent () {
this.$emit('updateProfile')
}
Parent Template:
<ChildComponent v-on:updateProfile="someMethod"/>
Parent Method:
someMethod () {
//GET request or whatever
}
More details here: https://v2.vuejs.org/v2/guide/components-custom-events.html
The keyword here is eventBus, you need an eventBus to $emit an event changing the data in the parent component from the grandchild component. If you only need to change up the data 1 layer instead of 2 in this case, you only need custom event + $emit, without the eventBus. But as it's greater than 2 layers, you need eventBus, or even more relegent ways to do state management.

Prop inheritance from component

Not too sure if i understand "Non-prop attributes" from manual (or vue.js at all): https://v2.vuejs.org/v2/guide/components-props.html
Say i have ChildComponent.vue file:
<template>
<input type="text" class="input" :value="childValue" v-on="listeners">
</template>
<script>
export default {
props: {
childValue: {
type: String,
default: 'blah',
}
},
computed: {
listeners() {
return {
// Pass all component listeners directly to input
...this.$listeners,
// Override input listener to work with v-model
input: event => this.$emit('input', event.target.value)
}
}
}
}
</script>
Then I add it to ParentComponent like this:
<template>
<ChildComponent v-model="parentValue" placeholder="default" #keydown.enter="parentMethod"/>
</template>
<script>
export default {
data () {
return {
parentValue: "",
};
},
methods: {
parentMethod () {
...
}
},
}
</script>
The flow should be (and works like this) - anything written to text field in ChildComponent after pressing enter should be sent all the way up to ParentComponent as parentValue and parentMethod() should be invoked.
If I understand correctly BasicComponent is kind of extension to its template's root component, meaning <input> will not only have props type and class set, but also placeholder (which has "default" value)?
Also, does this mean that the v-model prop to whom parentValue data is assigned will be propagated to <input> element as well, making my :value and v-on bind reduntant?
Another question - how the hell is v-on="listeners" working without specifying an event, does it mean i'm listening to EVERY event?
In the parent component there is a shorthand #keydown.enter which means it's listening for keydown.enter event, yet in listeners() method I'm emitting an input event...
I also have big trouble understanding what is going on in listeners() method at all, so any help in deciphering this will be greatly appreciated. :D
Thanks in advance for help.
Cheers
Let's do this one topic at a time...
Difference between props and non-prop attributes:
Props are the parameters which you define in your props object. With props you can tell the user what types they should use for a given prop, whether they're required or not, default values, assign validation functions, and etc.
Also, props are reactive, so if your template depends on a prop and the prop updates, so will your template.
Attributes you assign to your components, but do not correspond to any props, are passed to the $attrs variable. You can use it to access those values, like $attrs.id to get the id, or $attrs.name to get the name, and so on.
The event flow in your case:
Yes, the things you type on your ChildComponent are passed to ParentComponent. They are passed both via your v-model and via #keydown.enter="parentMethod".
You probably know how events work, but if you don't, here's the gist of it: When you need to pass data from a child component to a parent component, you emit an event in your child and listen to it in your parent.
For example, if you want to emit an event called foo, you would call $emit somewhere in your child, using $emit('foo'). Then, you'd listen to it in the parent by adding #foo="yourHandler" to the child, where yourHandler is a function written to handle the event. Which is what you did with #keydown.enter="parentMethod".
<input> will not only have props type and class set, but also placeholder (which has "default" value)?:
Answer: It depends. What the <input> tag in your template will receive depends on whether or not your root element (<input>) inherits component attributes. That behavior is defined by the inheritsAttrs property of a component, which defaults to true.
What that means is, in your case, since you haven't specified inheritsAttrs it will default to true, and yes, every attribute you pass to <ChildComponent> will be passed to your <input> tag, except for the things you defined manually.
Since you declared your <input> tag like this:
<input type="text" class="input" :value="childValue" v-on="listeners">
Your <input> tag will inherit all attributes from <ChildComponent> except type, value and your listeners (more on that later). The exceptions to that rule are class and style, which are always inherited regardless.
PS: Note that type, class and placeholder are attributes, not props.
Does this mean that the v-model prop to whom parentValue data is assigned will be propagated to element as well, making my :value and v-on bind reduntant?
Answer: No, but it also won't work. Here's why:
When you declare your listeners using this piece of code:
listeners() {
return {
// Pass all component listeners directly to input
...this.$listeners,
// Override input listener to work with v-model
input: event => this.$emit('input', event.target.value)
}
}
You are assigning to your listeners computed property every single event listener placed on your ChildComponent tag, including your keydown event, which is why it works.
The assignment is done in this line:
...this.$listeners,
It uses the spread operator to add all the elements in your $listeners variable (which holds all your component events) to the object you're returning.
The only event which you are not inheriting is input, as defined in this line:
input: event => this.$emit('input', event.target.value)
With that line, you tell your code that the behavior of your input event will be the one you defined, rather than the inherited.
Then, when you assign v-on="listeners" to your input, you're telling it to listen to every single event listed on your listeners variable. That is: You're appending all your inherited events and your custom input event to your input event.
Finally, to explain why it isn't redundant but why it won't work, you must understand how v-model works. It (usually) works by listening on the input event of a component, and using it to update the value prop of the same component. So in this line:
<ChildComponent v-model="parentValue" placeholder="default" #keydown.enter="parentMethod"/>
You are doing two things:
You're assigning the value of parentValue to the value prop of ChildComponent
You're telling your component to update parentValue whenever the input event is called.
That means that assigning a value and listeners to your input tag is not redundant, since you need it for v-model to work properly, but it won't work in the end, since your component doesn't have a value prop. it has a childValue prop instead.
To fix it, you have two options:
Rename childValue to value
Or tell your component to use childValue as model
To do the second approach, just append this piece of code to your ChildComponent:
model: {
prop: 'childValue',
event: 'input'
}
That will tell your component to use that prop and that event to make v-model work.
THE END
A final note: In the future, try narrowing your question down to a single topic. It will be easier to answer and will help people who search for those topics later on.