Extend Vue.js v-on:click directive - vue.js

I'm new to vuejs. I'm trying to create my first app. I would like to show a confirm message on every click on buttons.
Example:
<button class="btn btn-danger" v-on:click="reject(proposal)">reject</button>
My question is: Can I extend the v-on:click event to show the confirm everywhere? I would make my custom directive called v-confirm-click that first executes a confirm and then, if I click on "ok", executes the click event. Is it possible?

I would recommend a component instead. Directives in Vue are generally used for direct DOM manipulation. In most cases where you think you need a directive, a component is better.
Here is an example of a confirm button component.
Vue.component("confirm-button",{
props:["onConfirm", "confirmText"],
template:`<button #click="onClick"><slot></slot></button>`,
methods:{
onClick(){
if (confirm(this.confirmText))
this.onConfirm()
}
}
})
Which you could use like this:
<confirm-button :on-confirm="confirm" confirm-text="Are you sure?">
Confirm
</confirm-button>
Here is an example.
console.clear()
Vue.component("confirm-button", {
props: ["onConfirm", "confirmText"],
template: `<button #click="onClick"><slot></slot></button>`,
methods: {
onClick() {
if (confirm(this.confirmText))
this.onConfirm()
}
}
})
new Vue({
el: "#app",
methods: {
confirm() {
alert("Confirmed!")
}
}
})
<script src="https://unpkg.com/vue#2.2.6/dist/vue.js"></script>
<div id="app">
<confirm-button :on-confirm="confirm" confirm-text="Are you sure?">
Confirm
</confirm-button>
</div>

I do not know of a way to extend a directive. It is easy enough to include a confirm call in the click handler. It won't convert every click to a confirmed click, but neither would writing a new directive; in either case, you have to update all your code to use the new form.
new Vue({
el: '#app',
methods: {
reject(p) {
alert("Rejected " + p);
}
}
});
<script src="//cdnjs.cloudflare.com/ajax/libs/vue/2.3.4/vue.min.js"></script>
<div id="app">
<button class="btn btn-danger" #click="confirm('some message') && reject('some arg')">reject</button>
</div>

Related

How can i refresh only nuxt component in Nuxt?

i want refresh my component after add something. İ try
refresh() {
this.$nuxt.refresh()
}
this but not working this is truelly
Here is my idea to refresh the component. Base on your issue, you can use some ways to achieve this goal. But in my opinion, there is a way that you can bind a key to your component, and by changing the key, your component will refresh.
I implement a simple example to show you how it works:
Vue.component('button-counter', {
data() {
return {
count: 0
}
},
template: '<button #click="count++">You clicked me {{ count }} times.</button>'
})
new Vue({
el: '#app',
data: {
component_key: 0
},
methods: {
refreshComponent() {
this.component_key += 1
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.min.js"></script>
<div id="app">
<button #click="refreshComponent()">
Refresh Compoenent
</button>
<button-counter :key="component_key" />
</div>
You can click on the right button in the above example and see the count is going up. After that, when you click on the Refresh Component button, you see that the component refreshes.
Also, you can use this.$forceUpdate() to refresh all of your variables. Maybe it'll help with your situation, but I recommend the key binding solution for your issue.

VueJs: bind `v-on` on a custom component to replace an existing one

In order to ease the styling of my page, I'd like to create a bunch of mini components like, and exploit how attributes are merged in VueJs. So for example, here is a minimal js file also hosted on this JSFiddle:
Vue.component('my-button', {
template: '<button style="font-size:20pt;"><slot></slot></button>'
})
var app = new Vue({
el: "#app",
data: {
message: "world",
},
methods: {
sayHello: function () {
alert("Hello");
}
}
})
and then in my html I just want to use <my-button> instead of button:
<div id="app">
Hello {{message}} <my-button #click="sayHello" style="color:red;">Style works, but not click</my-button> <button v-on:click="sayHello" style="color:red;">Both works</button>
</div>
Unfortunately, it seems that attributes are merged, but not listeners, so it means that I can't do v-on:click on my new button... Any way to make it possible?
Thanks!
-- EDIT --
I saw the proposition of Boussadjra Brahim of using .native, and it works, but then I found this link that explains why it's not a great practice and how to use v-on="$listeners" to map all listeners to a specific sub-button. However, I tried, to just change my template with:
template: `<button style="font-size:20pt;" v-on="$listeners"><slot></slot></button>`,
but I get an error:
Vue warn: Property or method "$listeners" is not defined on the instance but referenced during render. Make sure to declare reactive data properties in the data option."
Here is the JSFiddle.
Your fiddle didn't work because you were using an old version of Vue, $listeners was added in Vue 2.4.0.
Here's a demo:
Vue.component('my-button', {
template: '<button style="color: red" v-on="$listeners"><slot/></button>'
})
new Vue({
el: '#app',
methods: {
sayHello() {
alert('Hello')
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<my-button #click="sayHello">Custom Button</my-button>
<button #click="sayHello">Ordinary Button</button>
</div>

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);
}

Basic radio validation with vee-validate

I'm attempting to incorporate vee-validate validation (version 2) against a basic/simple radio input, such as:
<div id="app">
<form id="webform" action='post.php' method='POST' #submit.prevent="doSubmit()">
<input type='radio' name='color' value='blue'> Blue<br>
<input type='radio' name='color' value='pink'> Pink
</form></div> <!-- div id app -->
<script>
Vue.use(VeeValidate);
new Vue({
el: "#app",
template: '#app',
data() {
return {
p_arr_condition_id: null,
};
},
methods: {
doSubmit() {
this.$validator.validateAll().then(function(result){
if (!result){
//this means a validation failed, so exit without doing anything
return;
}
//here you would put your form submit stuff
window.onbeforeunload = null;
document.getElementById('webform').submit();
});
}
}
});
</script>
But I'm unsure where to begin. I discovered a working example here, however I'm not showing how to actually implement their example. Their Docs link results in a 404.
Any help/guidance would be super appreciated.
The demo iframe has a not-so-obvious slider on the left side that allows you to see the code used in the example. You can also go directly to the code sandbox

Is it possible to globally bind to a change event?

I would like to trigger a method everytime the user switches to another field in a form. This does the job:
new Vue({
el: "#root",
data: {
theContent1: "",
theContent2: ""
},
methods: {
changeFun() {
console.log('change')
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.6/vue.js"></script>
<div id="root">
<form>
<input v-model="theContent1" #change="changeFun()">
<input v-model="theContent2" #change="changeFun()">
</form>
</div>
It is however repetitive when there are many fields. Is there a way to globally bind to a method for any change?
Note: I do not want to set a watch on the content of data - I need the method to be trigerred when the edited element changes, not when its content does. A practical example would be a submit once a field is completed and the user leaves it (but wihout submitting at each change of the value of the field while it is edited).
Just put your event listener at the root of your div. All Dom events traverse the Dom down from the root, to the element that generated the event, then back up again ! You can listen for them at any level. Use event.target and event.currentTarget to find out what generated the event and what captured it.
Note that, for this reason, it's super agressive to stop the propagation of an event. All kinds of things above your element might have an interest in the events it generates.
new Vue({
el: "#root",
data: {
theContent1: "",
theContent2: ""
},
methods: {
changeFun(event) {
console.log('change from '+event.target.id)
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.6/vue.js"></script>
<div id="root" #change="changeFun">
<form>
<input id="one" v-model="theContent1">
<input id="two" v-model="theContent2">
</form>
</div>
You could use watchers:
new Vue({
el: "#root",
data: {
theContent1: "",
theContent2: ""
},
watch: {
theContent1(newVal) {
console.log('change from theContent1: ', newVal)
},
...
}
})
With this you'll have to set watchers for each too...