Reputation: 15
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 complete, 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
Upvotes: 1
Views: 11072
Reputation: 20844
You 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.com/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>
Upvotes: 2
Reputation: 630
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.....';
}
}
}
Upvotes: 1
Reputation: 189
you can use $event to change the inner html for buttons
$event.path[0].innerHTML = "Write the inner html"
Upvotes: 0
Reputation: 29169
Hide the button and show the spinner using a data or computed property. Update the 'busy' property from your async function.
<button v-if='!busy' @click="defaultPermissionState(perm.id,'grant',$event)">Deny</button>
<spinner v-else />
Upvotes: 0
Reputation: 4656
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
Upvotes: 2