0

i am trying to validate an address:

  line1: Yup.string()
    .test(
      "Address Line 1 Validation Test",
      "Please enter valid Line 1 address",
      async (line1: string) => {
        let delayTimer = null;
        let isValid = false;
        const doSearch = () => {
          clearTimeout(delayTimer);
          delayTimer = setTimeout(async () => {
            const { data } = await axios.get<{ status: string }>(
              "https://maps.googleapis.com/maps/api/geocode/json?components=country:USA",
              {
                params: {
                  address: line1,
                  key: GEOCODE_API_KEY,
                },
              }
            );
            console.log("line1: ", line1);
            console.log("data: ", data);
            isValid = data.status === "OK" ? true : false;
          }, 1000); // Will do the ajax stuff after 1000 ms, or 1 s
        };
        doSearch();
        return isValid;
      }
    )
    .required("Line 1 is required"),

i want to integrate delay search like this so i don't flood my api everytime user type like this: AJAX: Delay for search on typing in form field

but it's doing api request everytime user type. how do i implement?

gpbaculio
  • 5,693
  • 13
  • 60
  • 102

1 Answers1

1

The problem is that you are actually never clearing the timeout.

Each time your handler runs, new delayTimer, isValid and doSearch variables are created and initialized. Those variables have to be placed in an outer scope. Something like this:

let delayTimer = null;
let isValid = false;

Yup.string()
    .test(
        'Address Line 1 Validation Test',
        'Please enter valid Line 1 address',
        async (line1: string) => {
            clearTimeout(delayTimer);
            
            delayTimer = setTimeout(async () => {
                const {data} =
                    (await axios.get) <
                    {status: string} >
                    ('https://maps.googleapis.com/maps/api/geocode/json?components=country:USA',
                    {
                        params: {
                            address: line1,
                            key: GEOCODE_API_KEY
                        }
                    });
                console.log('line1: ', line1);
                console.log('data: ', data);
                isValid = data.status === 'OK';
            }, 1000); // Will do the ajax stuff after 1000 ms, or 1 s
            
            return isValid;
        }
    )
    .required('Line 1 is required');

Now, even if that fixes your initial problem, there is another issue to address. Your function will always return a promise with the wrong value of isValid.

What you have to do depends on what you want, but I'll give you the following insight:

let delayTimer = null;
let isValid = false;
let resolveRef = null;

Yup.string()
    .test(
        'Address Line 1 Validation Test',
        'Please enter valid Line 1 address',
        async (line1: string) => {
            clearTimeout(delayTimer);

            if (resolveRef) {
                resolveRef(isValid);
                resolveRef = null;
            }

            return await new Promise((resolve) => {
                resolveRef = resolve;
                delayTimer = setTimeout(async () => {
                    const {data} =
                    (await axios.get) <
                    {status: string} >
                    ('https://maps.googleapis.com/maps/api/geocode/json?components=country:USA',
                        {
                            params: {
                                address: line1,
                                key: GEOCODE_API_KEY
                            }
                        });

                    isValid = data.status === 'OK';

                    resolve(isValid);
                    resolveRef = null;
                }, 1000);
            });
        }
    )
    .required('Line 1 is required');

Hope it works. Please let me know.

Ernesto Stifano
  • 3,027
  • 1
  • 10
  • 20