Closed jagged3dge closed 7 years ago
Seems I jumped the gun a bit. I just had to simplify the asyncValidateCheck
function to get it to work.
Current setup that works for me:
import fetch from 'isomorphic-fetch'
// import apiUrl from 'shared/ApiUrl'
import debounce from 'debounce-promise' // bjoerge/debounce-promise
// import debounce from 'es6-promise-debounce' // digitalbazaar/es6-promise-debounce
// import debounce from 'promise-debounce' // jaz303/promise-debounce
const asyncValidateCheck = (key, value) => {
const apiUrl = require('shared/ApiUrl').default
return fetch(`${apiUrl}/CheckUnique?${key}=${value.trim()}`, {
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json;charset=UTF-8'
},
method: 'post'
})
.then(checkStatus)
.then((data) => {
return data.hasOwnProperty('isUnique')
? data.isUnique
: false
})
.catch((err) => {
log('[AsyncValidator]', 'err =', err)
return false
})
}
export default debounce(asyncValidateCheck, 500)
… and in Validations.js
unique: () => {
const cachedResults = {}
return {
isValid: (value, data, revalidate) => {
if (!value) return true
const key = data.arg.toLowerCase()
const cacheKey = key + ':' + value
if (cachedResults[cacheKey] === undefined) {
cachedResults[cacheKey] = 'pending'
AsyncUniqueValidator(key, value)
.then((isUnique) => {
cachedResults[cacheKey] = isUnique
revalidate()
})
}
return cachedResults[cacheKey]
},
errorMessage: (value, { arg }) => `This ${arg.toLowerCase()} is already in use.\nPlease choose a different ${arg.toLowerCase()}`
}
}
yes, looks quite similiar to what I am doing :)
import debounce from "lodash/debounce";
const unique = getUrl => {
const cachedData = {};
const check = debounce((value, cb) => {
cachedData[value] = "pending";
fetch(getUrl(value)).then(res => {
if (res.status < 300) {
cachedData[value] = res.jsonData.ok;
cb();
} else {
return Promise.reject({status: res.status, error: new Error(res.jsonData.error)});
}
}).catch(e => console.warn(e));
}, 200);
return (value, ctx, validateAgainCb) => {
if (cachedData[value] === undefined) {
if (value) {
check(value, validateAgainCb);
return "pending";
} else {
cachedData[value] = true;
}
}
return cachedData[value];
};
};
it can be used like this:
const uniqueEmail = () => {
return {
isValid: unique(email => `/services/check-email-unique?${stringify({email})}`),
errorMessage: () => "This email address is already registered",
hintMessage: () => "Needs to be a unique email"
};
Is it possible ? Having an input trigger asynchronous (w/ Promises) validation requests at every keystroke is detrimental to the server throughput. I'd like to debounce the asynchronous validation function so that it only triggers after at least 500ms have passed since the last keystroke.
I have tried to figure this out using a few debounced promise implementations published over npm. No luck so far.
Has anyone achieved this?
Here's my relevant asynchronous validation function:
AsyncUniqueValidator.js
When typing into the textbox, the network tab in Chrome's DevTools looks like this:
The image shows no debounce is actually happening. I've tried debouncing the return function altogether. That does no change to the waterfall of network requests on typing.
Would you kindly point me in the right direction?