form(#submit.prevent="onSubmit")
input(type="text" v-model="platform" placeholder="Add platform name...")
input(type="submit" value="Submit" class="button" #click="clicked = true")
button(type="button" value="Cancel" class="btn" #click="cancelNew") Cancel
h3(v-if="clicked") Thank you for adding a new platform
span {{ countdown }}
This is my template and when the user submits the form, I want to count down from 3 using setTimeout function and submit after 3 seconds.
If I have it this way, it works;
data() {
return {
countdown: 3,
platform: ""
}
},
methods: {
countDownTimer() {
setTimeout(() => {
this.countdown -= 1
this.countDownTimer()
}, 1000)
},
onSubmit() {
let newplatform = {
name: this.platform
}
this.addPlatform(newplatform)
this.platform = ' '
this.countDownTimer()
}
}
However I have 3 more forms and I didn't want to repeat the code. So I wanted to put countdown in the store,
countDownTimer({commit}) {
setTimeout(() => {
countdown = state.countdown
countdown -= 1
commit('COUNTDOWN', countdown)
this.countDownTimer()
}, 1000)
}
and mutate it like
COUNTDOWN(state, countdown) {
state.countdown = countdown
}
This doesn't work and I am not sure If I am able to change the state, commit the changes inside of settimeout function? Is there a better way I can implement this?
The issues:
The recursive setTimeout isn't stopped.
The countdown timer isn't reset.
Use setInterval (and clearInterval) instead of the recursive setTimeout.
For async logic including setTimeout, use an action rather than a mutation.
Include state from the context object (where you get commit), or it will be undefined.
Try this:
actions: {
countDownTimer({ state, commit, dispatch }) { // state, commit, dispatch
commit('RESET');
const interval = setInterval(() => { // Use `setInterval` and store it
commit('COUNTDOWN');
if (state.countdown === 0) {
clearInterval(interval); // Clear the interval
dispatch('updateDatabase'); // Call another action
}
}, 1000)
}
}
mutations: {
RESET(state) {
state.countdown = 3;
},
COUNTDOWN(state) {
state.countdown--;
}
}
Related
I have a v-textarea, I write something to area and if I do not any action, in v-textarea context must be cleared automatic after a certain time (2 minutes). How can I do it?
<v-textarea
v-model.trim="text"
clearable
:label="modeLabel"
>
I would do something like this with a timer.
<v-textarea
v-model.trim="text"
clearable
:label="modeLabel"
#change="clearHandler(event)"
>
var timerID = null;
function clearHandler() {
if (timerID) {
clearTimeout(timerID);
}
// create a timer to clear the textarea by setting the model to empty string
timerID = setTimeout(() => {
this.text = "";
}, 120000);
}
Also, I would use this.timerID or a ref variable, instead of var like my example, depending on what version of vue you are using.
I've created this with a simple watcher. First, we create a function that includes the timeout. After that we create a watcher triggered to val. In this watcher, we call the timeout and after that clear the timeout. The reason for this is that we want it to re-run the function. The watcher also watches the value, if the user enters sth, the timeout will be canceled.
new Vue({
el: "#app",
data() {
return {
val: ''
}
},
methods: {
timeout() {
return setTimeout(() => {
this.val = ''
}, 5000)
}
},
watch: {
val: {
handler() {
this.timeout()
clearTimeout(this.timeout);
}
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<input v-model="val" />
</div>
I have a child component that emits a value, and in the parent I perform an axios call with this value each time it is emitted. My problem is that I want to trigger the axios call only if in x ms (or seconds) the child has not emmited another value in order to reduce the amount of calls I do.
Code here :
<script>
import axios from "axios";
import DataTable from './DataTable.vue';
export default {
name: 'Test',
data() {
return {
gamertags: [],
// Utils
timeout: 500,
delay: 500
}
},
methods: {
// API calls
async getGamerTags(string='') {
const path = `http://localhost:5000/gamertags?string=${string}`
await axios.get(path)
.then((res) => {
this.gamertags = res.data;
})
.catch((error) => {
console.error(error);
});
},
// DataTable
handleFilters(filters) {
clearTimeout(this.timeout);
this.timeout = setTimeout(this.getGamerTags(filters.find(o => o.field == "playerGamerTag").filter), this.delay);
}
}
components: {
DataTable
}
};
</script>
<template>
<DataTable
#filters="handleFilters"
/>
</template>
Thanks in advance.
What you need is debouncing. Here is an example:
var timeout, delay = 3000;
function func1() {
clearTimeout(timeout);
timeout = setTimeout(function(){
alert("3000 ms inactivity");
}, delay);
}
<input type="text" oninput="func1()">
When emitted, simply call func1(), and if there are no new emissions after 3000 ms, the function in timeout will be executed.
It would be better to understand the problem and use case if you add the code also.
but As I could understand the problem these is two way
if you using inside input and triggering based #changed event you can add #change.lazy this not trigger on each change.
second solution is to use setTimeout(function,delayInMs) inside parent
vuejs Docs link
By simply changing the handleFilters function to :
handleFilters(filters) {
clearTimeout(this.timeout);
this.timeout = setTimeout(
this.getGamerTags,
this.delay,
filters.find(o => o.field == "playerGamerTag").filter
);
},
the problem is solved.
So I have a vuetify simple table that displays available times to book appointments. However, this times are pull from a database and that information get changes every 5 minutes (based on people that booked or cancel). The user will need to refresh the table to get the latest changes. Im trying to introduce some sort of auto refresh in VueJs that reloads the data every 5 minuts. this is my method that is been called right now
created(){
this.fetchAvailableTimeSlotsData75();
},
method:{
fetchAvailableTimeSlotsData75() {
this.$axios.get('appointments75', {
params: {
date: this.isCurrentMonth(this.strSelectedDate) ? '' : this.strSelectedDate,
week: this.intPageNumber
}
})
.then((objResponse) => {
if(objResponse.status == 200){
// console.log(objResponse.data)
this.total = objResponse.data.total;
this.arrAvailableDates = objResponse.data.dates;
this.arrAppointmentsData = objResponse.data.data;
this.getAppointments();
}
})
.catch((objError) => {
})
.finally(() => {
this.blnLoading = false;
this.snackbar = false
});}
}
Whats the best way to approach this in VueJs? Any Ideas?
To put it simply, use setInterval:
var _timerId;
export default {
data: () => ({
pollingInterval: 1000 * 60 * 5
}),
created() {
this.startPolling(true);
},
methods: {
startPolling(init = false) {
if (init) {
// Call it immediately
this.fetchAvailableTimeSlotsData75();
this.startPolling();
return;
}
_timerId = setInterval(this.fetchAvailableTimeSlotsData75, this.pollingInterval);
}
},
// Optional
destroyed() {
clearInterval(_timerId);
}
}
Is it possible to have a global variable in store? I want to create/remove an interval I use for polling an API. Right now I do the following:
const refreshData = null;
export default {
namespaced: true,
state: {
...
},
mutations: {
...
},
actions: {
pollForData() {
// Make API call
.
.
.
// Set interval to poll every 5 seconds if the data has a certain flag
if(res.data.update) {
if(!refreshData) {
refreshData = setInterval(() => {
dispatch('pollForData');
});
}
} else {
if(refreshData) {
clearInterval(refreshData);
refreshData = null;
}
}
}
}
}
This works perfectly, but the variable lying outside is bothering me. Because I don't know if this is the right way to do it, and I think there must be a better way.
I want to perform autosave when a user fills out a form in a React component. The ajax call should be triggered when 3 seconds has passed since last onChange event.
My code below is inspired from an instructive article which shows how to accomplish this with setTimeout and clearTimeout. But I'm doing something wrong in my React implementation - the 3 sec delay isn't respected when typing.
Any ideas what's wrong here? Or is my thinking all together wrong about how to solve this?
class Form extends Component {
constructor() {
super();
this.state = {
isSaved: false
};
this.handleUserInput = this.handleUserInput.bind(this);
this.saveToDatabase = this.saveToDatabase.bind(this);
}
saveToDatabase() {
var timeoutId;
this.setState({isSaved: false});
if (timeoutId) {
clearTimeout(timeoutId)
};
timeoutId = setTimeout( () => {
// Make ajax call to save data.
this.setState({isSaved: true});
}, 3000);
}
handleUserInput(e) {
const name = e.target.name;
const value = e.target.value;
this.setState({[name]: value});
this.saveToDatabase();
}
render() {
return (
<div>
{this.state.isSaved ? 'Saved' : 'Not saved'}
// My form.
</div>
)
}
Inside saveToDatabase method you are defining a new and undefined timeoutId variable every time the method is called. That's why the if statement never gets called.
Instead, you need to scope out the variable and create a class data property in the constructor.
constructor() {
super();
this.state = {
isSaved: false
};
this.timeoutId = null;
this.handleUserInput = this.handleUserInput.bind(this);
this.saveToDatabase = this.saveToDatabase.bind(this);
}
saveToDatabase() {
this.setState({isSaved: false});
if (this.timeoutId) {
clearTimeout(this.timeoutId)
};
this.timeoutId = setTimeout( () => {
// Make ajax call to save data.
this.setState({isSaved: true});
}, 3000);
}