I have the following component:
<template>
<button class="button" @[click]="action">{{ text }}</button>
</template>
<script>
export default {
name: "Button",
props: {
action: {
type: Function,
required: false
},
text: {
type: String,
required: true
},
inputType: {
type: String,
required: false
}
},
computed: {
click() {
return this.action ? "click" : null;
}
}
};
</script>
However when I pass a function as the action with a parameter then the function is already triggered on render. Without a parameter it works fine.
<v-button inputType="button" :action="say('Hello')" text="Alert" />
<v-button inputType="button" :action="say" text="Alert" />
The triggered function:
say(message) {
alert(message);
}
You can see the behaviour here. Looking at this I would expect it to work with passing params.
So my question is how can I prevent the trigger on render?
$emitInstead of passing a function into the child component, you could instead emit a clicked event; e.g:
<button class="button" @click="$emit('clicked')">{{ text }}</button>
Then listen to the emitted event on the component itself, triggering your function:
<v-button inputType="button" @clicked="say('Hello')" text="Alert" />
Although emitting and handling events is a neat way to communicate from a child component to its parent, it can break down somewhat when the component emitting the event is not a direct descendant; e.g: where the component is a grandchild.
Vue does not implicitly bubble events up through the component tree, I believe this is by design to ensure event behaviour is explicit.
<slot>In this case, it's often desirable to use slots to create a component that as access to the scope in which it was created, but then nest it within another child component.
<modal>
<v-button @clicked="say('hi)" text="Alert"/>
</modal>
Otherwise, if you need to pass a function to a child component, and that function also has an argument, you'll have to create it as a higher-order function.
In your case, you want to pass the say method to a child, with an argument. You want to pass the function but not invoke it, but when you pass an argument to say() you are invoking it there and then:
<v-btn :action="say('hi')">
The solution here is to rewrite say so it also returns a function, which will then be invoked when the button is clicked:
say (message) {
return () => alert(message)
}
This implies that you must invoke the say method when passing it to the button component even if you are not passing a message to that button instance. So, the following will work:
<v-button :action="say()" text="Alert"/>
But this will not because it does not invoke the inner function:
<v-button :action="say" text="Alert"/>
Hope this helps :)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With