Hello Developer, Hope you guys are doing great. Today at Tutorial Guruji Official website, we are sharing the answer of Access drag-n-drop object inside Promise.then()? without wasting too much if your time.
The question is published on by Tutorial Guruji team.
The question is published on by Tutorial Guruji team.
Problem
I try to access dataTransfer object. It works fine in top-level code but return undefined inside Promise.prototype.then().
After drag and drop files, Result is
LOG#1 = [object DataTransferItem] LOG#2 = undefined
Example of real code (simplified from actual project):
function dropHandler(e) { let fileNameList = []; let promise = new Promise((resolve, reject) => { console.log('File(s) dropped'); e.preventDefault(); if (e.dataTransfer.items) { // Get list of all dropped file name. for (var i = 0; i < e.dataTransfer.items.length; i++) { if (e.dataTransfer.items[i].kind === 'file') { fileNameList.push(e.dataTransfer.items[i].getAsFile().name); } } // Read text from pairs.txt. let pairsIndex = fileNameList.map(str => str.toLowerCase()).indexOf("pairs.txt"); let pairsFile = e.dataTransfer.items[pairsIndex].getAsFile(); console.log(pairsFile); console.log("LOG#1 = " + e.dataTransfer.items[0]); pairsFile.text().then(text => { console.log("LOG#2 = " + e.dataTransfer.items[0]); resolve(); }); } }); promise.finally(() => { e.dataTransfer.items.clear(); fileNameList = []; }); } function dragOverHandler(e) { console.log('File(s) in drop zone'); // Prevent default behavior (Prevent file from being opened) e.preventDefault(); }
#drop_zone { border: 3px dashed; width: 100%; height: 300px; }
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <h5>Instruction: Drag and drop files to make quiz.</h5> <div id="drop_zone" ondrop="dropHandler(event);" ondragover="dragOverHandler(event);"> <i class="bi bi-file-arrow-up" style="font-size: 10rem; color: rgb(189, 189, 189);"></i> <p>Drag one or more files to this Drop Zone ...</p> </div> </body> </html>
Question
- Why result at LOG#2 is undefined while result at LOG#1 work fine? Is there any way to access it?
Answer
Once you call .then()
you’re no longer in the original call stack of the function. This is something that would matter particularly in the event listener.
We can reproduce the same effect with setTimeout:
e.preventDefault(); console.log(e.dataTransfer.items); setTimeout(()=> { console.log(e.dataTransfer.items); })
Results in :
DataTransferItemList {0: DataTransferItem, 1: DataTransferItem, 2: DataTransferItem, 3: DataTransferItem, length: 4} DataTransferItemList {length: 0}
Hence the context of DataTransfer
is lost with time. One approach is to copy required data before missing and reuse it when needed:
const items = [...e.dataTransfer.items];
function dropHandler(e) { let fileNameList = []; let promise = new Promise((resolve, reject) => { console.log('File(s) dropped'); e.preventDefault(); if (e.dataTransfer.items) { // Get list of all dropped file name. for (var i = 0; i < e.dataTransfer.items.length; i++) { if (e.dataTransfer.items[i].kind === 'file') { fileNameList.push(e.dataTransfer.items[i].getAsFile().name); } } // Read text from pairs.txt. let pairsIndex = fileNameList.map(str => str.toLowerCase()).indexOf("pairs.txt"); // const items = [...e.dataTransfer.items]; // const pairFiles = items[pairsIndex].getAsFile(); // New code as per comment const items = [...e.dataTransfer.items].map(item => item.getAsFile()); let pairsFile = items[pairsIndex]; console.log(pairsFile); console.log("LOG#1 = " + items[0]); pairsFile.text().then(text => { console.log("LOG#2 = " + items[0]); resolve(); }); } }); promise.finally(() => { e.dataTransfer.items.clear(); fileNameList = []; }); } function dragOverHandler(e) { console.log('File(s) in drop zone'); // Prevent default behavior (Prevent file from being opened) e.preventDefault(); }
#drop_zone { border: 3px dashed; width: 100%; height: 300px; }
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <h5>Instruction: Drag and drop files to make quiz.</h5> <div id="drop_zone" ondrop="dropHandler(event);" ondragover="dragOverHandler(event);"> <i class="bi bi-file-arrow-up" style="font-size: 10rem; color: rgb(189, 189, 189);"></i> <p>Drag one or more files to this Drop Zone ...</p> </div> </body> </html>
We are here to answer your question about Access drag-n-drop object inside Promise.then()? - If you find the proper solution, please don't forgot to share this with your team members.