I’m new to Vue and Javascript in general and am currently trying to figure out how to pass data from a child component to a parent component. I’m trying to write a simple calculator, but I’ve run into the following problem. My calculator is split into several components, namely Button
, ButtonPanel
, Display
and Calculator
(required). The ButtonPanel consists of number buttons and arithmetic buttons. Each button has props btnValue
. The expression
variable is declared in the Calculator component, and my task, when you click on the corresponding button, is to add its value to the one that is displayed. The problem is that when the button is clicked, instead of its btnValue, btnValue[object PointerEvent]
is added to expression. What is the problem and is there a way around it?
This is my sources:
Calculator.vue:
<template>
<div class="calculator-container">
<Display :expression="expression || '0'"></Display>
<ButtonPanel @update-expression="updateExpression"></ButtonPanel>
</div>
</template>
<script>
import Display from "@/components/Display";
import ButtonPanel from "@/components/ButtonPanel";
import {ref} from "vue";
export default {
name: 'CalculatorComponent',
components: {ButtonPanel, Display},
props: {},
setup() {
const expression = ref('');
const updateExpression = (value) => {
expression.value += value;
};
return {
expression,
updateExpression
}
}
}
</script>
//Styles, etc
Button.vue
<template>
<div class="button" @click="handleClick(this.btnValue)">
<h2 class="text-white m-0">{{btnValue}}</h2>
</div>
</template>
<script>
export default {
// eslint-disable-next-line vue/multi-word-component-names
name: 'Button',
props: {
btnValue: String
},
methods:{
handleClick(value){
console.log(value)
this.$emit('click',value);
}
}
}
</script>
ButtonPanel.vue:
<template>
<div class="button-panel">
<Button @click="addToExpression" btn-value="1"></Button>
<Button @click="addToExpression" btn-value="2"></Button>
//other-buttons
</div>
</template>
<script>
import Button from "@/components/Button";
export default {
name: 'ButtonPanel',
components: {Button},
methods:{
addToExpression(value){
console.log(value)
this.$emit('update-expression',value)
}
}
}
</script>
2
Answers
Ok, changing the name of event to
btn-click
, whichButton.vue
produces, worked for me. If I understood correctly,@click
is kind of reserved name for event and it produces PointerEvent object, so you have to give it a custom name, and then subscribe to this event in parent componentThe issue comes from not declaring the events your component emits:
As it says in the documentation:
So when you are not declaring the custom
click
event, the@click
listener on theButton
components will be triggered by the event emitted from the Button component, but also by the native click event bubbling upwards from thediv.button
element. The bubbling event will contain the native click event object.Have a look at the snippet, I hope it demonstrates the difference between declaring the event and not doing so: