Vue : Custom parameter [duplicate] - vue.js

I pass a parameter in v-on:input directives. If I don't pass it, I can access the event in the method. Is there any way I can still access the event when passing the parameter to the function? Note that I am using vue-router.
This is without passing the parameter. I can access the event object:
HTML
<input type="number" v-on:input="addToCart" min="0" placeholder="0">
Javascript
methods: {
addToCart: function (event) {
// I need to access the element by using event.target
console.log('In addToCart')
console.log(event.target)
}
}
This is when passing the parameter. I can't access the event object:
HTML
<input type="number" v-on:input="addToCart(ticket.id)" min="0" placeholder="0">
Javascript
methods: {
addToCart: function (id) {
// How can I access the element by using event
console.log('In addToCart')
console.log(id)
}
}
Here is a fiddle of the code, it should be good enough to replicate the problem that I am having:
https://jsfiddle.net/lookman/vdhwkrmq/

If you want to access event object as well as data passed, you have to pass event and ticket.id both as parameters, like following:
HTML
<input type="number" v-on:input="addToCart($event, ticket.id)" min="0" placeholder="0">
Javascript
methods: {
addToCart: function (event, id) {
// use event here as well as id
console.log('In addToCart')
console.log(id)
}
}
See working fiddle: https://jsfiddle.net/nee5nszL/
Edited: case with vue-router
In case you are using vue-router, you may have to use $event in your v-on:input method like following:
<input type="number" v-on:input="addToCart($event, num)" min="0" placeholder="0">
Here is working fiddle.

You can also do something like this...
<input #input="myHandler('foo', 'bar', ...arguments)">
Evan You himself recommended this technique in one post on Vue forum. In general some events may emit more than one argument. Also as documentation states internal variable $event is meant for passing original DOM event.

Depending on what arguments you need to pass, especially for custom event handlers, you can do something like this:
<div #customEvent='(arg1) => myCallback(arg1, arg2)'>Hello!</div>

I like this way of passing parameters because we can pass events and parameters both using an anonymous callback function.
<button v-on:click="(e)=>deleteHandler(e, args1)" > Click me </button>

Related

What's the difference in Vue #click between calling a method directly and calling in inside a function

I'm learning nuxt and the tutor has a function to add an item called updateTodo and attached it to a button as the follwoing
script
<script setup>
const updateTodo = async (id) => {
if (!input) return;
await $fetch(`/api/todo/${id}`, { method: 'PUT' });
};
</script>
template
<template>
<div class="container">
<input type="text" placeholder="Add a new todo..." v-model="input" />
<NButton #click="() => updateTodo(todo.id)">Add</NButton>
</div>
</template>
I dont know why he didn't call it directly (eg. #click="updateTodo(todo.id)). I tried to do it and it worked. Is there a reason i dont know or it's just a preference?
Both are allowed.
https://vuejs.org/guide/essentials/event-handling.html#listening-to-events
The usage would be v-on:click="handler" or with the shortcut, #click="handler". The handler value can be one of the following:
Inline handlers: Inline JavaScript to be executed when the event is triggered (similar to the native onclick attribute).
Method handlers: A property name or path that points to a method defined on the component.
However, note that this isn't necessarily always the case. In some libraries/frameworks, something like onclick="yourFunction()" might call the method immediately, and use the returned value as an event listener. This is usually not what you want, unless you're returning a function.
in this case you call directly, you don't require event parmas here.
<NButton #click="updateTodo(todo.id)">Add</NButton>
but in a certain case, you need event parament to get the value of the input (e.target.value) or want to prevent the default of that event(e.preventDefault) i.e
a. you call anyFunction in each time, then
<input #input="anyFunction">
b. but you want to pass function if enter value is greater than 100 or anything else then you need to pass as function so you get event as params like
<input #input="(e) => e.target.value > 100 && anyFunction">
In other words, if there is no argument in the function for the particular event then you don't need to pass the function. else you need to pass the function.

Vuejs keyup event trigger with keyCode and condition

I wanted to bind an event on condition and trigger it only when the user enters a particular key, For example,
I want to bind the event when the value of the label equal to tags
onTagAdd($event, index) : {} }" v-model="value">
onTagAdd: function (oEvent, index){
if(oEvent.key === ";"){
//some code
}
}
It's working as expected.
Further, I wanted to trigger the event only when ; (virtual key code = 186) pressed, so I have tried below code
onTagAdd($event, index) : {} }" v-model="value">
It is not working. I have referred vue.js documentation But, haven't got any workaround.
How to do this?
Note: I have eliminated this approach as it's giving me an error in IE for $event. still looking for the solution if any which solves the problem and support the browser compatibility.
Try this out and tell me if it worked.
<input type="text" v-on:keyup.186="{ (label == 'Tags') ? $event => onTagAdd($event, index) : {} }" v-model="value">
maybe the inline style doesn't support keycode in event type(not sure),try this out:
<input type="text" v-on:keyup.186="onTagAdd($event,2)" v-model="value">
methods: {
onTagAdd(event,index){
// put your logic codes here
console.info('==')
console.info(event)
console.info(index)
}
}
This page was helpful for me in Vue3: https://v3-migration.vuejs.org/breaking-changes/keycode-modifiers.html
3.x Syntax#
Since KeyboardEvent.keyCode has been deprecated, it no longer makes sense for Vue 3 to continue supporting this as well. As a result, it is now recommended to use the kebab-case name for any key you want to use as a modifier.
<!-- Vue 3 Key Modifier on v-on -->
<input v-on:keyup.page-down="nextPage">
<!-- Matches both q and Q -->
<input v-on:keypress.q="quit">
As a result, this means that config.keyCodes is now also deprecated and will no longer be supported.
TLDR: in Vue 3 keycodes appear to be deprecated in favour of using kebab case.
For example, #keyup.186 would be #keyup.;

VueJs - preventDefault() on form submission

I need to submit a form programmatically, but I need it to preventDefault as well.
Right now I have the following:
submit() {
this.$refs.form.submit()
}
It is working fine, but I cannot prevent default on the submit which in the end, refreshes the page.
Short answer
You can add the .prevent modifier to the #submit (or any other v-on you're using), like this:
<form #submit.prevent="myMethod">
<button type="submit"></button>
</form>
In the case of submitting a form, this will prevent the default behavior of refreshing the page.
Long answer
There are several ways to modify events.
From the Vue 3 docs:
It is a very common need to call event.preventDefault() or
event.stopPropagation() inside event handlers. Although we can do this
easily inside methods, it would be better if the methods can be purely
about data logic rather than having to deal with DOM event details.
To address this problem, Vue provides event modifiers for v-on. Recall
that modifiers are directive postfixes denoted by a dot.
<!-- the click event's propagation will be stopped -->
<a #click.stop="doThis"></a>
<!-- the submit event will no longer reload the page -->
<form #submit.prevent="onSubmit"></form>
<!-- modifiers can be chained -->
<a #click.stop.prevent="doThat"></a>
<!-- just the modifier -->
<form #submit.prevent></form>
<!-- use capture mode when adding the event listener -->
<!-- i.e. an event targeting an inner element is handled here before being handled by that element -->
<div #click.capture="doThis">...</div>
<!-- only trigger handler if event.target is the element itself -->
<!-- i.e. not from a child element -->
<div #click.self="doThat">...</div>
Another option:
Sometimes we also need to access the original DOM event in an inline statement handler. You can pass it into a method using the special $event variable:
<button #click="warn('Form cannot be submitted yet.', $event)">
Submit
</button>
// ...
methods: {
warn: function (message, event) {
// now we have access to the native event
if (event) {
event.preventDefault()
}
alert(message)
}
}
Cheers :)
Didn't quite understand #Armin Ayari's answer, for instance why the code would have to be in the methods object? Anyway in Vue this is what worked for me:
<form ref="form" #submit.prevent="myMethod">
<button type="submit"></button>
</form>
This blocked the page from refreshing and called myMethod instead.
You don't even need the ref. Understood this is an old question, but I found myself here after debugging, and found my form tags were simply mis-placed.
I don't know if I understood your question correctly but you can prevent the default behavior of your form like this:
this.$refs.form.addEventListener("submit", (event) => {
event.preventDefault()
});
Maybe this can help you:
new Vue({
el: '#app',
data: {},
methods: {
submit () {
this.$refs.form.addEventListener('submit', event => {
event.preventDefault()
})
},
alert () {
alert('hello')
}
}
})
<body>
<script src="https://cdn.jsdelivr.net/npm/vue#2.5.17/dist/vue.js"></script>
<div id='app'>
<div class="form-wrapper" #click='submit'>
<form ref='form' #submit='alert'>
<input type="text">
<button type='submit'>Submit</button>
</form>
</div>
</div>
</body>
I think it's dona help!!
<form method="POST" action="http::localhost:8080/" #submit.prevent="submit_login($event)">
// enter yours inputs here
</form>
submit_login(e) {
if (true) {
e.target.submit();
},
},
After some proper investigation with not a single answer here being related to the original question.
I have found your solution, however it isn't VueJS specific, referencing this article: Javascript e.preventDefault(); not working on submit()
Answer
Your programmatic way to execute submit this.$refs.form.submit() isn't correct if you want to properly preventDefault() or even run other functions.
You need to run this.$refs.form.requestSubmit(), this replicates the functionality as if you would've had a child <button> run the clicked event.
First, don't use preventDefault method. I will illustrate this problem on jQuery:
$('#myForm').on('submit', function (event) {
// step 1.
// stop current action, prevent submitting
event.preventDefault()
// step 2.
// validate inputs
// some validation code
// step 3.
// everything ok, submit it
this.submit()
})
Where is problem with this code? When you submit this form programatically in step 3., it will be again captured and will stop at step 1. again. So, you will be never able to submit this form. Solution:
$('#myForm').on('submit', function (event) {
// step 1.
// validate inputs
// some validation code
// this code will be always executed
// before this form will be submitted
// step 2.
// then do something like this
// continue submitting form and exit
// this callback with returning true
if (inputsAre === 'ok') return true
// if inputs are not ok, program continues
// with following line, which ends this
// callback with false and form will be not submitted
return false
})
I hope you got the point. So, I think what you need is not the preventDefault method, but return true or return false in your doSomething method called on #submit event.

How create a v-model modifier to a VueJS Component?

In VueJS there is some v-model modifies that pre-parse the binded value, for instance v-model.trim that removes whitespaces from the string.
How can I create my own modifier? for instance v-model.myparse
Today um using something like:
computed: {
name: {
get: function () { return parse(this._name);},
set: function (value) { _name = parse(value);}
}
What is very verbose.
I would it to be reusable to do something like:
<input v-model.myparse="name" name='n1'/>
<input v-model.myparse="name" name='n2'/>
<input v-model.myparse="name" name='n3'/>
<input v-model.myparse="name" name='n4'/>
computed properties with setters seems to do part of the work, but it is really useful with some few variables only, it becomes very verbose with a lot of properties.
First, adding adding a custom modified to v-model is under discussion but not yet implemented.
If it was implemented, you could extend the v-model and add a modifier to it.
Since that is not possible, you have a couple of options left, one of which is to use :value instead of v-model. Because v-model is just a syntactic sugar of following:
<input type="text" :value="message" #input="message = $event.target.value">
The above code is the same as:
<input type="text" v-model="message">
So, I suggest you replace the logic for the #input to something like this:
<input type="text" :value="message" #input="getModel">
Now, you can use a function to return a modified value as:
methods: {
getModel ($event) {
return $event.target.value.trim()
}
}
But all of what I mentioned can still be done with the v-model if you use a function.
Of course it goes without saying, you can create your own custom directive also.

closure within v-for, attribute interpolation

I have this basic setup
<div v-for="n in 4">
<some-component #on-some-event="onSomeEvent(n)"></some-component>
</div>
the on-some-event is dispatched within some-component. but I need to know which of these components sent the message. with the setup above, only n is passed into the method. and the data that the event sends is nowhere.
I'd like to interpolate the function so that the method looks like this
onSomeEvent(n){
return (obj)=>{
console.log(`component ${n} sent ${obj}`);
};
}
but wrapping onSomeEvent with {{}} throws a warning: attribute interpolation is not allowed in Vue.js directives and special attributes.
I could just pass the n index into the component but that seems less elegant because I may not have the ability to modify some-component
I am somewhat new to Vue, so perhaps I am missing some core functionality for this type of thing?
<div v-for="n in 4">
<some-component #on-some-event="onSomeEvent | pass n"></some-component>
</div>
....
filters: {
pass(handler, n) {
return function() {
handler()(n, ...arguments)
}
}
},
methods: {
onSomeEvent() {
console.log(...arguments)
}
}
https://jsfiddle.net/2s6hqcy5/2/
You didn't miss anything, the message is correct, in Vue, you won't be able to use interpolation like that.
http://vuejs.org/guide/syntax.html#Interpolations
However, you may want to change how you manage events and pass data between components. In your example, you can just bind the data like this:
<div v-for="n in 4">
<some-component :n="n"></some-component>
</div>
In your component, declare the prop:
Vue.component('some-component', {
props: ['n'],
...
Now, inside each component, you have the n available like any other property (http://vuejs.org/guide/components.html#Props).
Then when dispatching your event, you can call it like this, with no need for a param:
onSomeEvent()
On the event itself, you can access the n:
console.log('Component' + this.n + ...)
https://jsfiddle.net/crabbly/mjnjy1jt/