I my app UI I have a table with a set of permissions listed. In each row there is a toggle-button that sets the default state of each permission to either "deny" or "grant" in the DB.
If the user clicks the button, async action is triggered in the background. It all works perfectly fine, but what I want to add is when user click the button its inner html changes to a spinner or some sort of "wait..." text and the button get disable while the action runs. This is to prevent user from clicking multiple time is the action take a bit longer to plete, giving impression like nothing is happening.
Now, I know how to do it in jQuery or even plain JS, but I have no idea how to access the button properties in VUE.js
My button look like this:
<button @click="defaultPermissionState(perm.id,'grant',$event)">Deny</button>
I'm only recently started into vue.js, so still learning it ;)
UPDATE: I've actually managed to find a way to do it by exploring the $event and being able to change the text and button properties by doing this:
event.path[0].innerHTML = 'wait...';
event.path[0].disabled = true;
but this does not look like a very elegant solution, so if anyone knows of something better I would still like to hear it
I my app UI I have a table with a set of permissions listed. In each row there is a toggle-button that sets the default state of each permission to either "deny" or "grant" in the DB.
If the user clicks the button, async action is triggered in the background. It all works perfectly fine, but what I want to add is when user click the button its inner html changes to a spinner or some sort of "wait..." text and the button get disable while the action runs. This is to prevent user from clicking multiple time is the action take a bit longer to plete, giving impression like nothing is happening.
Now, I know how to do it in jQuery or even plain JS, but I have no idea how to access the button properties in VUE.js
My button look like this:
<button @click="defaultPermissionState(perm.id,'grant',$event)">Deny</button>
I'm only recently started into vue.js, so still learning it ;)
UPDATE: I've actually managed to find a way to do it by exploring the $event and being able to change the text and button properties by doing this:
event.path[0].innerHTML = 'wait...';
event.path[0].disabled = true;
but this does not look like a very elegant solution, so if anyone knows of something better I would still like to hear it
Share Improve this question edited Apr 9, 2019 at 8:41 ps-hyp-pt asked Apr 9, 2019 at 8:26 ps-hyp-ptps-hyp-pt 151 gold badge2 silver badges5 bronze badges 2-
bind the disabled attribute
:disabled="isLoading"
– Socrates Tuas Commented Apr 9, 2019 at 8:39 - @Socrates Tuas - except that the table can have many row, 50+ even, depending what's in the database, so if I set isLoading to true then all my buttons will change state – ps-hyp-pt Commented Apr 9, 2019 at 8:50
5 Answers
Reset to default 2You can use v-if
with :disabled
. Check this quick example:
new Vue({
el: "#app",
data: {
isLoadingArray: []
},
methods: {
clicked(index) {
this.$set(this.isLoadingArray, index, true)
setTimeout(() => {
this.$set(this.isLoadingArray, index, false)
}, 2000)
}
}
})
.lds-dual-ring {
display: inline-block;
width: 64px;
height: 64px;
}
.lds-dual-ring:after {
content: " ";
display: block;
width: 46px;
height: 46px;
margin: 1px;
border-radius: 50%;
border: 5px solid #fff;
border-color: #fff transparent #fff transparent;
animation: lds-dual-ring 1.2s linear infinite;
}
@keyframes lds-dual-ring {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
<script src="https://cdnjs.cloudflare./ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<button type="button" @click="clicked(0)" :disabled="isLoadingArray[0]">
<div v-if="isLoadingArray[0]" class="lds-dual-ring"></div>
<span v-else>click me</span>
</button>
<button type="button" @click="clicked(1)" :disabled="isLoadingArray[1]">
<div v-if="isLoadingArray[1]" class="lds-dual-ring"></div>
<span v-else>click me</span>
</button>
<button type="button" @click="clicked(2)" :disabled="isLoadingArray[2]">
<div v-if="isLoadingArray[2]" class="lds-dual-ring"></div>
<span v-else>click me</span>
</button>
</div>
You can do it like this
data: function() {
return {
waiting: false,
...otherstuffs
}
},
methods: {
callAsync() {
this.waiting = true;
callASYNC()
.then((result) => {
this.waiting = false;
})
}
}
In your HTML
<button :disabled="waiting"> {{ waiting ? 'Waiting ...' : 'Deny' }} </button>
So basically, just set a flag before you hit the request, and set it back when the call finishes. Use this flag to set the button value to whatever you want
This should help
<template>
<button disabled={{disableBtn}}
@click="defaultPermissionState(perm.id,'grant',$event)">{{btnText}}
</button>
</template>
export default {
data() {
return {
btnText: 'Deny',
disableBtn: false
}
},
method: {
defaultPermissionState(id, type, e) {
this.disableBtn = true;
this.btnText = 'Clicking.....';
}
}
}
Hide the button and show the spinner using a data or puted property. Update the 'busy' property from your async function.
<button v-if='!busy' @click="defaultPermissionState(perm.id,'grant',$event)">Deny</button>
<spinner v-else />
you can use $event to change the inner html for buttons
$event.path[0].innerHTML = "Write the inner html"