Access drag-n-drop object inside Promise.then()? Code Answer

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.

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.

Related Posts

Tutorial Guruji