noszone
noszone

Reputation: 328

Fetch blob downloaded status in a function

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);

Upvotes: 0

Views: 1952

Answers (1)

noszone
noszone

Reputation: 328

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);
            })();

Upvotes: 2

Related Questions