0

I am generating an excel file on server NodeJS side, by request from the React frontend side. What can I use - some type of event or promise in order to verify if blob downloading process is finished? I need this status to set a Button element loading state while file is downloading.

React client side function:

export const download = (url, filename) => {
    fetch(url, {
        mode: 'no-cors' 
        /*
        * ALTERNATIVE MODE {
        mode: 'cors'
        }
        *
        */
    }).then((transfer) => {
        return transfer.blob();                // RETURN DATA TRANSFERED AS BLOB
    }).then((bytes) => {
        let elm = document.createElement('a');  // CREATE A LINK ELEMENT IN DOM
        elm.href = URL.createObjectURL(bytes);  // SET LINK ELEMENTS CONTENTS
        elm.setAttribute('download', filename); // SET ELEMENT CREATED 'ATTRIBUTE' TO DOWNLOAD, FILENAME PARAM AUTOMATICALLY
        elm.click();                             // TRIGGER ELEMENT TO DOWNLOAD
        elm.remove();
    }).catch((error) => {
        console.log(error);                     // OUTPUT ERRORS, SUCH AS CORS WHEN TESTING NON LOCALLY
    })
}

I've tried:

To return a false in .then(bytes) block, to use async, await in fetch. Only the result I got is console.log in where .then(bytes) block gives a proper sync:

 }).then((bytes) => {
            console.log("Downloaded, working");
            let elm = document.createElement('a');  // CREATE A LINK ELEMENT IN DOM
            elm.href = URL.createObjectURL(bytes);  // SET LINK ELEMENTS CONTENTS

The oher ways immideatelly sets variable (I know because of promise), so Butoon spin is not sync(1 second) with download process (3 seconds). Is there any other ways possibly?

Initial client-side request:

fetch('/api/hrreportdetailed', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify(
                {state}
                )
            });
            download('/api/hrreportdetailed',"Report "+getDDMMYYY(new Date())+".xlsx");
            setBtnLoad2(variable);
noszone
  • 190
  • 1
  • 14
  • 1
    Your question is quite unclear. Could you ask someone around to reformulate it a bit? Namely, it's not clear if all you want is to know when the downloading is finished, or if you want a kind of progress event while downloading. Ps: I expect it to be a dupe of https://stackoverflow.com/questions/47285198/fetch-api-download-progress-indicator, but maybe simply reacting to the first Promise of `fetch()` may be enough (the browser is actually downloading between `fetch().then()` and `response.[consume]().then()`) – Kaiido Jun 16 '21 at 06:27
  • @Kaiido I need just this function to wait(the real time while the excel file is generating) proper time(3 sec instead of 1), so I can use a setBtnLoad2(variable) as a true/false indicator in spinner component. – noszone Jun 16 '21 at 06:28
  • 1
    Then, `fetch( url ).then( (resp) => { is_downloading = true; return resp.blob(); } ).then( (blob) => { is_downloading = false; ... } )` would be all you need. – Kaiido Jun 16 '21 at 06:38

1 Answers1

1

I remade the function and now it's working as I expected:

export const download = async (url, filename) => {
    let response = await fetch(url, {
        mode: 'no-cors' 
        /*
        * ALTERNATIVE MODE {
        mode: 'cors'
        }
        *
        */  
    }); 
    try {
        let data = await response.blob();
        let elm = document.createElement('a');  // CREATE A LINK ELEMENT IN DOM
        elm.href = URL.createObjectURL(data);  // SET LINK ELEMENTS CONTENTS
        elm.setAttribute('download', filename); // SET ELEMENT CREATED 'ATTRIBUTE' TO DOWNLOAD, FILENAME PARAM AUTOMATICALLY
        elm.click();                             // TRIGGER ELEMENT TO DOWNLOAD
        elm.remove();
    } 
    catch(err) {
        console.log(err);
    }   
}

To call the function in code I've used anonymous function (normal func I hope also can be used):

(async () => {
                await download('/api/hrreportbyhours',"Report "+getDDMMYYY(new Date())+".xlsx");    
                await setBtnLoad1(false);
            })();
noszone
  • 190
  • 1
  • 14