How to get the value of button when clicked using vue.js - vue.js

I have several buttons on a page which are hooked to the same method webcamSendRequestButton
<button v-on:click="webcamSendRequestButton" value="0" type="button" class="webcam-send-request-button" :disabled="disabled">Verify</button>
<button v-on:click="webcamSendRequestButton" value="1" type="button" class="webcam-send-request-button" :disabled="disabled">Verify</button>
<button v-on:click="webcamSendRequestButton" value="2" type="button" class="webcam-send-request-button" :disabled="disabled">Verify</button>
<button v-on:click="webcamSendRequestButton" value="3" type="button" class="webcam-send-request-button" :disabled="disabled">Verify</button>
and I am making an ajax call when the button is clicked. In jquery or JS it is pretty straightforward to get the value of button when clicked using $(this).val();
How do I fetch the value of the button when it is clicked in vue?
var app = new Vue({
el: '#my-div',
methods: {
webcamSendRequestButton: function() {
const buttonValue = ??? // How do I fetch the value over here
$.ajax({
url: "someurl",
type: "POST",
data: {
value: buttonValue
},
success: function (data) {
// Omitted for brevity
}
});
}
}
});

A better answer than the previous ones I believe is to inject the original DOM '$event' variable into your handler call:
v-on:click="webcamSendRequestButton($event)"
And receive it in your handler:
methods: {
webcamSendRequestButton: function(e) {
const buttonValue = e.target.value;
.
.
.
}
}
This is better for two well-connected reasons.
First, the code now has the same reasoning behind the initial intention: When a button is clicked, the handler should be able to read the value of the button that initiated the event. Other solutions that pass the value statically to the handler only mimic this, thus being more or less a hack.
Second, because the code now exactly matches the initial intention, the code becomes more maintainable. For example, if the value of each button gets to change dynamically by being bound to a variable value instead of a static value, the handler needs not to be changed at all. If the buttons grow or shrink in number, there is no need to change the handler code or define extra references or change the syntax of the handler call.

You can simply give it as an argument to the function.
<button v-on:click="webcamSendRequestButton(0)" type="button" class="webcam-send-request-button" :disabled="disabled">Verify</button>
JS
...
methods: {
webcamSendRequestButton(value){
//"value" is the clicked button value
}
}
...

You can give your button a reference that Vue can access by giving it a tag ref="yourRef". Then you can access the value inside of your called function with this.$refs.yourRef.value.
Works for other Input elements as well ;)

I have a button group, and three buttons in it. I wanted to get the string from each button button when there is a change, and change my attribute to that string value when there is a change in button. I used #change event of vuejs and it worked for me. I will be pleased if it will be helpful for someone else too.
In template:
<div class="btn-group">
<button
type="button"
class="btn btn-md light btn__border"
v-on:change="latestType = 'week'"
>Week</button>
<button
type="button"
class="btn btn-md light btn__border"
v-on:change="latestType = 'month'"
>Month</button>
<button
type="button"
class="btn btn-md light btn__border"
v-on:change="latestType = ''"
>All</button>
</div>
In Js (script tag):
...
data() {
return {
latestType:''
}
}
...

One improvement over the accepted answer by reinarg is to access the button's value directly using event.srcElement. This way you don't have to pass an argument into webcamSendRequestButton in the template. In fact, the OP wouldn't have to change the template at all and would have to change only one thing in the method:
webcamSendRequestButton: function() {
const buttonValue = event.srcElement.value // This provides the button's value
$.ajax({
url: "someurl",
type: "POST",
data: {
value: buttonValue
},
success: function (data) {
// Omitted for brevity
}
});
}
This also avoids having to enter the same value in two places for each button (once in the value attribute and again as an argument for the webcamSendRequestButton method).

Related

Vue v-on:click change it to load or mouse over event

I am trying to get v-bind:value on to function reservationBy() as load event instead of v_on:clickevent. Right now it passes the value when I click on it only.
Is there a way to make it load automatically or use mouse over event? I even try to use v-on:load and v-on:focus event but it did not work.
View
<div id="app">
<input v-bind:value="2" v-on:click="reservationBy"/>
</div>
Script
new Vue({
el: "#app",
data: {
},
methods: {
reservationBy: function(e) {
var peopleBookedId = e.target.value;
console.log(peopleBookedId);
}
}
})
Here is example on JSFIDDLE
https://jsfiddle.net/ujjumaki/yz0p1vqL/4/
#mouseover and #mouseleave will do the job.
<input v-bind:value="2" #mouseover="reservationBy"/>
or
<input v-bind:value="2" #mouseleave="reservationBy"/>
If using v-model is not an option (that would be the easiest way), and you want to execute the function when component is rendered, you can use ref and access value in mounted hook:
<input ref="myInputRef" :value="2" />
Script:
mounted: function() {
console.log(this.$refs.myInputRef.value);
}

2 way binding is not working properly in vuejs

I have defined a vuejs component this way:
<template>
<form #submit.prevent="submit">
<textarea id="content" cols="30" rows="10" v-model="content">{{ content }}</textarea>
<button class="btn btn-lg btn-success" type="submit" #click="send()">
Send content
</button>
</form>
</template>
<script>
export default {
data() {
return {
content: '// Initial content'
}
},
methods: {
send() {
console.log('Content', this.content);
},
submit() {
return false;
}
},
mounted() {
console.log('Template init ', this.content);
}
}
</script>
When I click on send, the send method outputs the content of the textarea as expected. But when I change the content of the textarea with jquery:
$('#content').val(content);
and hit send, it doesn't update content in the template. "Send" outputs the old value.
can somebody please explain to me what's wrong here?
v-model is listening for an input event to trigger changing the value of its bound variable.
From the vue.js documentation:
v-model internally uses different properties and emits different
events for different input elements:
text and textarea elements use value property and input event;
checkboxes and radiobuttons use checked property and change event;
select fields use value as a prop and change as an event.
Using the JQuery val() method to select the element and change the value does not trigger an event that v-model is listening for, so the value of your bound variable does not change/update.
If you absolutely have to use JQuery to change the content, you could manually trigger an event that might also trigger the v-model binding to update:
$('#content').val(content).trigger('input');

Modal form Validation errors persist when reopened

About the problem
I am using Laravel 5.6.7, Vue.js. I have modal div which being opened and closed on button click. I type something. Validation fires. I close the modal div. Then clicking button to open it. I see that the validation messages still there.
Component Template
<template>
<div>
<form role="form">
<input name="LastName" type="text" ref="LastName" v-validate
data-vv-rules="required" v-model="createForm.LastName">
<p v-if="errors.has('LastName')">{{ errors.first('LastName') }}</p>
<button v-else type="button" #click="validateBeforeSubmit()">
Create
</button>
</form>
</div>
</template>
Component Script
<script>
export default {
data() {
return {
createForm: {
LastName: ''
}
};
},
created() {
this.InitializeForm();
},
methods: {
InitializeForm() {
this.createForm.LastName = "";
},
validateBeforeSubmit() {
this.$validator.validateAll();
}
}
}
</script>
My findings
if you check the input type text above, I added ref attribute. Tried the below code to set the value to false for aria-invalid attribute.
this.$refs.LastName.setAttribute("aria-invalid", "false");
It sets the attribute value but validation errors are still there. Is there any proper way to get rid of workarounds like above?
I think, when I set the first value or I click on it...some attribute value is being set and due to that form errors occur.
Assuming that you are using vee-validate,
To clear all errors,
this.$validator.errors.clear();
To clear 1 single error only,
this.$validator.errors.remove('LastName');
Add 1 of the code above to the modal close event listener and the error would be gone the next time you opened it..

Is it possible to access event listeners from component in Vue.js 2

I have a custom component in Vue.js(2) as:
Vue.component("modal-panel", {
props: {
id: {
required: true
},
title: {} ,
size: {
validator: function(value) {
return !value || value=="lg" || value=="sm";
}
},
confirmLabel: {
"default": "Yes",
},
closeLabel: {
"default": "No"
},
confirm: {
type: Function
}
},
//...
template: `
//...
<button type="button" class="btn btn-primary confirm" data-dismiss="modal" v-on:click="$emit('confirm')" v-if="confirm">{{confirmLabel}}</button>
//...
`
}
And this is the code using component
<modal-panel title="New User" id="userModal" #confirm="doSomething">...</modal-panel>
As seen from the component code, confirm has been inserted into the props and on the button code in the template there is a conditional rendering according to whether confirm listener attached or not. However, button is not rendered. I checked component dom and properties, but there is not such an info.
Is it possible to make conditional rendering according to whether a specific listener attached to component in vue.js?
Thanks.
Since Vue 2.4, Vue components have a $listeners property.
Contains parent-scope v-on event listeners (without .native
modifiers).
This is documented here. You can determine whether or not the parent is listening to a particular event by examining the $listeners property.
**Original Answer**
It's not generally good practice for a component to reach out of itself to determine things.
I would recommend instead that you have a confirm callback property. You can pass a function in as a property. Then you can decide to show/hide the button on whether you received the callback or not.
Vue.component("modal",{
props:["confirm"],
template: `
<div>
<h1>Modal</h1>
<button v-if="confirm" #click="confirm">Confirm</button>
</div>
`
})
Example.
Edit
You can determine if there is a handler defined on a component for a given event, but it requires examining an internal Vue property, and you should only use this at your own risk.
Vue.component("modal",{
template: `
<div>
<h1>Modal</h1>
<button v-if="hasConfirmHandler" #click="$emit('confirm')">Confirm</button>
</div>
`,
computed:{
hasConfirmHandler(){
return !!this._events["confirm"]
}
}
})
The _events property of the component will contain the handler, if a handler is defined from the parent.
Example.
You need to bind your function with v-bind or : instead of just passing it as a string. So use :confirm syntax:
<modal-panel title="New User" id="userModal" :confirm="doSomething"></modal-panel>
Then in component template simply use v-on:click="confirm()":
<button type="button" class="btn btn-primary confirm" data-dismiss="modal"
v-on:click="confirm()"
v-if="confirm">
{{confirmLabel}}
</button>

Lagging in v-on:change

I had an input with v-on:change directive in it to call some method I declared inside the Vue objects. But I realized there are delays in calling the method whenever the value is changed.
I reproduced it in here:
HTML
<div id="demo">
<input type="number" min=0 v-on:change="change">
<p>{{num}}</p>
</div>
Javascript
var data = {
num:0
}
var demo = new Vue({
el: '#demo',
data: data,
methods: {
change: function(event) {
console.log(event.target.value);
this.num = event.target.value;
}
}
})
https://jsfiddle.net/lookman/4y2wmxot/2/
There is no delay actually, unless you click outside the input field in result section, on-change will not be triggered. It is triggered when focus changes from the input field, as you have only one element this is triggered when you click manually in the result section.
If you just add one more component, like I did here, and now you enter some value and press tab, you will see change immediately, you can do this in your fiddle also, enter value and press tab (which will remove focus)
If you want to trigger on each change
You can use input event instead of change event to trigger the method for each change.
The DOM input event is fired synchronously when the value of an or element is changed.
Code changes:
<input type="number" min=0 v-on:input="change">
Update fiddle: https://jsfiddle.net/4y2wmxot/4/
For this use case, you really should be using v-model anyways:
<div id="demo">
<input type="number" min=0 v-model="num">
<p>{{num}}</p>
</div>
Then there's no need for the method at all:
var data = {
num:0
}
var demo = new Vue({
el: '#demo',
data: data,
})
try keyup instead change:
<input type="number" min=0 v-on:change="change">
https://jsfiddle.net/lookman/4y2wmxot/2/
will you face any limitation to prevent you to use another kind of event?