Debounced function calls delayed but all executed when wait timer ends - javascript

I am using debounce in order to implement a 'search as you type' field.
I am reading https://css-tricks.com/debouncing-throttling-explained-examples/ and from what I can understand the function should only be called a limited number of times.
In my case, the function calls are delayed, but executed all at once once the wait timer ends:
methods: {
searchOnType: function (currentPage, searchString) {
console.log(`Searching ${searchString}`)
var debounced = throttle(this.getMovies, 4000, {leading: false, trailing: true})
debounced('movies.json', currentPage, searchString)
},
getMovies: function (url, page, query) {
console.log(query)
this.loading = true
resourceService.getMovies(url, page, query).then((result) => {
this.items = result.movies
this.totalMovies = result.total
this.loading = false
})
},
the HTML (it's Vue.JS)
<input
type="text"
v-model="searchString"
class="form-control input-lg"
placeholder="search movie"
#keydown="searchOnType(currentPage, searchString)"
>
This is my console.log:

You're creating a throttled function every time you keydown (you should probably be using input instead by the way). You can do this instead I think...
methods: {
searchOnType: throttle((currentPage, searchString) => {
this.getMovies('movies.json', currentPage, searchString)
}, 1000, {leading: false, trailing: true})
}

Related

SweetAlert2 executing functions while showing loading showing success after done

I am trying to create a sweetAlert2 function where I want to fire a loading screen. And during the loading screen, I want to execute some functions, which can take some time. Afterward I want to display a fire success or error, depending on what the return will be. I tried several methods:
Swal.fire({
title: 'Auto close alert!',
html: 'In progress',
timerProgressBar: true,
didOpen: () => {
try {
Swal.showLoading();
call other functions..
if success show
Swal.fire({
icon: 'success',
title: 'Success...',
html: message
});
or else fire error
catch(err){
etc.
}
}
)};
Now when I execute the function it waits a few seconds (executing functions) and then it shows the success or error fire, but it doesn't show the in-progress loading dialog first. Any idea how to get this?
Fixed it by using setTimouts and promises:
//Start
Swal.fire({
title: 'In progress',
html: 'Please wait while your action is being carried out.',
timerProgressBar: true,
didOpen: () => {
//here it will open the in progress box
Swal.showLoading();
//setTimeout with 1000 or more ms is needed in order to show the inprogress box
setTimeout(async () => {
let currentRecID = currentRecord.get().id;
//load complete record
currentRec = record.load({
type: record.Type.OPPORTUNITY,
id: currentRecID,
isDynamic: true
});
const promiseVar = () =>
new Promise((resolve, reject) => {
resolve(canCreateORD(currentRec));
});
canORDbeCreated = await promiseVar();
//Automatically close popup so it continues with willClose
Swal.close();
}, 1000);
},
willClose: () => {
//Show success / error box with Swal.fire

Don't call popup if another one is already on the page

There is a popup (1) that should be called after 15 seconds of being on the page.
But if the user opened some other popup(2), then don't call the first one.
popup(1);
mounted() {
this.openModal();
},
// methods
openModal() {
setTimeout(() => {
this.isModalVisible = true;
}, 15000);
},
How to do it?
Perhaps need to stop setTimeOut?
Maybe something like following snippet:
new Vue({
el: '#demo',
data() {
return {
isModalVisible: false,
isModalOther: false
}
},
methods: {
openModal() {
setTimeout(() => {
if(!this.isModalOther) this.isModalVisible = true;
}, 5000);
},
openOtherModal() {
this.isModalVisible = false
this.isModalOther = true;
},
},
mounted() {
this.openModal();
},
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="demo">
<div v-if="isModalVisible">popup1</div>
<div v-if="isModalOther">popup2</div>
<button #click="openOtherModal">open popup2</button>
</div>
To cancel a timeout, all you need to do is call clearTimeout(TimeoutID);. A timeoutID is a returned by the setTimeout() method automatically, so just save it in a variable
let timer = setTimeout(...);
then, when you call popup(2), just add
this.clearTimeout(timer);
and the first popup won't show

Awaiting till user finishes writing to input field in Vue.js

I have a QR code creating page. I want my QR codes to be created dynamically by user input. But I don't want to instantly create a QR code. I want to wait my user to finish writing then after one second i will generate the QR code. So I have a template like below:
<div class="app">
<qrcode-vue :value="genaratedQrCode"></qrcode-vue>
<input type="text" v-model="qrCodeInput" />
</div>
And my script:
import QrcodeVue from 'qrcode.vue';
export default {
data() {
return {
genaratedQrCode: '',
qrCodeInput: '',
isInputFunctionRunning: false
}
},
watch: {
async qrCodeInput() {
if (this.isInputFunctionRunning) {
return;
}
this.isInputFunctionRunning = true;
await new Promise(r => setTimeout(r, 1000));
this.genaratedQrCode = this.qrCodeInput;
this.isInputFunctionRunning = false;
}
}
components: {
QrcodeVue,
},
}
Apparently the code is not working. It generated the QR code every one seconds. What I want is waiting till user finished, then updating after 1 seconds.
You have to use .lazy modifier :
<input type="text" v-model.lazy="qrCodeInput" />
If you want to wait some delay try this :
import QrcodeVue from 'qrcode.vue';
function debounce (fn, delay) {
var timeoutID = null
return function () {
clearTimeout(timeoutID)
var args = arguments
var that = this
timeoutID = setTimeout(function () {
fn.apply(that, args)
}, delay)
}
}
export default {
data() {
return {
genaratedQrCode: '',
qrCodeInput: '',
isInputFunctionRunning: false
}
},
watch: {
qrCodeInput:debounce(function() {
if (this.isInputFunctionRunning) {
return;
}
this.isInputFunctionRunning = true;
this.genaratedQrCode = this.qrCodeInput;
this.isInputFunctionRunning = false;
},1000)
}
components: {
QrcodeVue,
},
}
This is based on this answer;

Laravel vue infinite scroll won't pull new data

I am using element UI and it has infinite scroll with it, but i can't get it to work in my app.
Code
script
data() {
return {
count: '', // default is 8
total: '', // defalt is 15
perPage: '', // default is 8
loading: false,
products: [],
}
},
computed: {
noMore () {
return this.count >= this.total // if this.count (8) reach this.total (15) then show no more text.
},
disabled () {
return this.loading || this.noMore
}
},
methods: {
load () {
this.loading = true
setTimeout(() => {
this.count += this.perPage // add 8 more to page
this.loading = false
}, 1000)
},
getProducts: function(){
axios.get('/api/products').then(response => {
this.products = response.data.data;
this.count = response.data.meta.per_page; // set count to 8 (backend based)
this.perPage = response.data.meta.per_page; // set perPage to 8 (backend based)
this.total = response.data.meta.total; // my testing data are 15 so it sets total to 15 (backend based)
}).catch((err) => console.error(err));
}
},
mounted() {
this.getProducts();
}
HTML
<div class="row mt-5 my-5 infinite-list" v-infinite-scroll="load" infinite-scroll-disabled="disabled"> // load function
<div class="col-md-3 mb-3" v-for="product in products" :key="product.slug" :offset="1"> // loop function
<el-card shadow="hover" :body-style="{ padding: '0px' }">
{{product.name}}
</el-card>
</div>
// infinite functions
<div class="col-md-12 mt-3" v-if="loading">
<el-card shadow="always" class="text-center">Loading...</el-card>
</div>
<div class="col-md-12 mt-3" v-if="noMore">
<el-card shadow="always" class="text-center">That's it, No more!</el-card>
</div>
</div>
Meta data
Result
What did I do wrong in my code?
its because of your load function take look on it,
load () {
this.loading = true
setTimeout(() => {
this.count += this.perPage // add 8 more to page
this.loading = false
}, 1000)
},
you have set time out for 1000 ms which is called after each scroll
first count is updated by fetch call and then second time its updated by time out call back of load function ,
instead of making this.loading =false after 1000 ms you should make it false on success of fetch call and same thing apply for updating this.count, hope this will help you.
EDIT:
your load function should be like following
load () {
this.loading = true
this.getProducts();//previously you getproduct is called once only after mounted,you you need to call it each time whenever load is called
},
and you fetch function should be like
getProducts: function(){
axios.get('/api/products').then(response => {
this.products = response.data.data;
this.count += this.perPage // add 8 more to page
this.loading = false
this.perPage = response.data.meta.per_page; // set perPage to 8 (backend based)
this.total = response.data.meta.total; // my testing data are 15 so it sets total to 15 (backend based)
}).catch((err) => console.error(err));
}
another thing you can try is ,use getProducts instead of load and remove load function, make this.loading=true in your getProducts function,
previously your getProducts is called only once when component is mounted.you need to call getProducts function each time whenever load more is requested.

React function loose state on second try

this code works properly on first and third try, there's always a step where it bugs and send no data to the db, it ruin my business logic every time, I tried with and without page reload got the same results
apiCall = e => {
e.preventDefault();
window.scrollTo(0, 0);
this.setState({ loading: true });
const { currentUser } = fire.auth();
let userEmail = currentUser.email;
let userUnderscore = userEmail.replace(/\./g, '_');
let intervalMS = this.state.interval * 60000;
let url = `https://url.com/api/v1/${userUnderscore}/${this.state.urlTask}?url=${this.state.urlTask}&width=${this.state.width}&interval=${intervalMS}&user=${userUnderscore}&running=true`;
if (this.state.interval >= 1 && this.state.urlTask !== "") {
fetch(url)
}
else {
this.setState({ addURLError: true, loading: false });
}
this.setState({ addURL: true, addURLError: false });
fire.database().ref(`/master/users/${userUnderscore}/setup/`)
.update({
running: true,
interval: this.state.interval,
url: this.state.urlTask,
});
setTimeout(
function () {
this.setState({ addURL: false, running: true });
window.location.reload();
}.bind(this), 2000
);
}
...
<Button color='black' onClick={this.apiCall} animated='vertical' type='submit'>
EDIT
The function and the db actually get updated, the issue is that on second try the state is empty even if the form hold values
I fixed the issue by reloading the app before any attempt of executing the function, that way there's always a fresh state to be used : window.location.reload();

Categories

Resources