Vue $emit fires but parent component method does not trigger - vue.js

I've been trying to pass data from child to parent. I'm not quite sure why what I've got right now isn't working. I should mention that the emitter gets fired but the method in the parent component doesn't seem to get called.
Children.vue:
<div #click="removeCommercials()" class="">
<u-button icon color="transparent">
<u-icon icon="switch-on" color="white"/>
</u-button>
</div>
methods: {
removeCommercials () {
this.$emit('test',{message:'HELLOOOO???'})
console.log("AAA")
}
},
Parent.vue:
<Children class="mt-4" #test="noCommercials"/>
methods: {
noCommercials(deactivate) {
console.log("?????")
this.deactivateCommercials = deactivate.message
console.log("REMOVEING COMMERCIALS")
console.log(this.deactivateCommercials)
},
},
From the console I can see the text AAA. From the vue developer tools I can also see the emitter getting fired with the correct data. But the method noCommercials in the parent component doesn't seem to trigger. Nothing from the method gets printed in the console.
From some other posts I've seen people talking about using this.$parent.$emit instead of this.$emit but that didn't do the trick for me. I've also seen others having the same problem but that's because they used the wrong child component.
I'm really confused as to why the noCommercials method does not trigger at all in the parent component. What am I doing wrong?
ADDITIONAL INFO:
I tried to trigger the same method from a different child component with $emit and it works. Now I just need to figure out why this particular child component is giving me issues.

Related

Why aren't there props for child -> parent and $emits for parent -> child?

I have a page with a component and the page needs to access a variable in that component. Would be nice if it were reactive. Then from the page I need to activate a function in the component. Would be nice if it could be done without a reactive variable. My question is 1: what's the best way to activate the function from the parent, for example when I click a button and 2: it seems very unintuitive and random to me that they aren't both possible in both directions? Anyone maybe know how Vue suggest you do it? This whole thing seems so complex relative to the relatively simple thing I'm trying to do.
I guess I try to use props? Or are refs a better option here?
So in general: you use refs, if you need the dom element, that's the whole purpose of refs. Since you don't mention that you n ed the dom element, you don't need to use that here.
There are 3 ways of communication: parent to child via props: https://vuejs.org/guide/components/props.html
child to parent via events
https://vuejs.org/guide/components/events.html
and anyone to anyone via event bus, which need an extra lib in vue3 and is out of scope for your question
https://v3-migration.vuejs.org/breaking-changes/events-api.html#event-bus
If you want to execute a function in the component whenever the value changes, you can put a watcher on the prop.
The other way around, from child to parent, you just create a listener to your emitted event and invoke a function of your choice. There are good examples in the docs in my opinion.
As per my understanding, You want to trigger the child component method from the Parent component without passing any prop as a input parameter and in same way you want to access child component data in the parent component without $emit. If Yes, You can simply achieve this using $refs.
You can attach the ref to the child component and then access it's variables and methods with the help of this $refs.
Live Demo (Just for a demo purpose I am using Vue 2, You can make the changes as per Vue 3) :
Vue.component('child', {
data: {
childVar: ''
},
methods: {
triggerEventInChildFromParent() {
console.log('Child Function triggered from Parent');
}
},
mounted() {
this.childVar = 'Child component variable'
}
});
var app = new Vue({
el: '#app',
methods: {
triggerEventInChild() {
this.$refs.child.triggerEventInChildFromParent()
}
},
mounted() {
console.log(this.$refs.child.childVar)
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<button #click="triggerEventInChild">
Button in Parent
</button>
<child ref="child"></child>
</div>

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.

VueJS emitted event not getting picked up by parent component

I am struggling to understand why an emitted event on a child component is not getting picked up by the parent.
The event is getting emitted from the child component - I can see it in the toolbar along with the correct values. The method that is tied to the event is not getting called on the parent component. ChildComponent.vue is a form that is imported into ParentComponent.vue.
Here is what I have (that's working but not).
ParentComponent.vue
<child-component/>
<div v-show="this.label === 'acme'" #label:name="handleLabelName">
<h3>Hello World</h3>
...
</div>
...
methods: {
handleLabelName(name) {
console.log('handleManualType called'); // never getting here
console.log('name: ', name); // never getting here
}
},
ChildComponent.vue
...
<button data-label="acme" #click="handleClick($event)">Click Me</button>
...
methods: {
handleClick(event) {
const label = event.target.dataset.label;
this.$emit('label:name', label); // acme
},
The event is getting broadcast, but handleLabelName is never getting called. I've read through this great article many times and I believe I'm following it correctly. Is there something I am doing wrong to make handleLabelName never get called? I've also tried wrapping everything in a div like so:
<div #label:name="handleLabelName">
<div v-show="this.label === 'acme'">
<h3>Hello World</h3>
...
</div>
</div>
And still the same result. handleLabelName never gets called. I've also tried changing the event name/method to simple things like, foo and still no difference.
Thank you for any suggestions!
You are listening for events on a div instead of listening to your child component. You must put your listener on the DOM element that sends the event. Try something like this :
<child-component #my-event-name="handleLabelName"/>
Another point is that you might prefer using kebab case to name your custom events. It might be a problem to name your event with this character ":" (see https://v2.vuejs.org/v2/guide/components-custom-events.html)

Vue component state freezing when moved between router-views

I have a custom map component, which wraps a Openlayers 4 instance. This component which I am forced to use, is used multiple places across my SPA. The initialization process is quite long, so I would like to keep one instance of the map available, and move it between views when I need to. Problem is that the state doesen´t update within the component when it has moved.
I´ve boiled the problem down to this fiddle: https://jsfiddle.net/j16d4yto/
When moved on the same router-view the state updates fine (click the ‘Change text’ button). But when the router-view changes, and the component is moved with appendChild to the new div, the state freezes, and you can´t update the text variable anymore.
This is how I move the component from one element to another:
this.$root.$on('showMoveableComponent', function(element) {
element.appendChild(thisElement);
this.text = 'Changed text2';
});
I bet I am doing something wrong here, and probably also approaching this problem in the wrong way?
Thanks!
It's not working because of when router-view changed your MoveableComponent has been destroyed only its DOM element still referenced by you. You can test by print something in destroyed lifecycle callback function.
So this mean you can solve this by using built-in keep-alive component:
<keep-alive>
<router-view></router-view>
</keep-alive>
Example
The keep-alive component will cache everything which may not good in some other cases.
In my opinion the better way to solve this is create another Vue instance and move it.
const MoveableComponent = new Vue({
el: '#some-id',
template: `...`,
data: { ... },
methods: {
changeText() {
...
},
moveTo(element) {
element.appendChild(this.$el)
}
}
})
Example

Vue.js - access to data from slot's component

I have a problem with accessing data from the component using slots.
Here's my code:
codepen.io/anon/pen/BbOEZz
I want the line:
<p slot="desc">{{ desc_01 }}</p>
It started working and at the slot in the template displayed the value with date.
Can anyone help me with this matter?
There are a couple of mistakes in your code
1.You don't access data directly from the child. The child communicates with the parent via events, using emit.
You should
fire an event from the child
listen to the event on the parent
update a variable on the parent.
2.There is no desc_01 declared on the app. The template is executed in the context of the app and not the child, so you also need to define that property.
data () {
return {
desc_01: ''
}
}
I've added a code pen for this here.