skip to Main Content
 <input type="file" @change="handleUpdateFIle">

I’m having trouble running the following code snippet in my application. When I try to set the src of an img element using the result of a FileReader object, I get an error saying "img src is not valid". Can you help me fix this issue?

const handleUpdateFIle = (e: file) => {
  const file= e.target.files[0]
  const reader = new FileReader()
  const img = new Image()
  reader.onload = () => {
      const arrayBuffer = reader.result
      const blob = new Blob([arrayBuffer],{type: file.type || 'image/png'})
      console.log('blob',blob)
      const URL = window.URL || window.webkitURL
      const url = URL.createObjectURL(blob)
      img.src = url
   //img.src blob:http:xxx
  }
  reader.readAsArrayBuffer(file)
}

console tip

Uncaught (in promise) img src is not valid

I’ve tried using readAsDataURL instead of readAsArrayBuffer, but I still get the same error. Can you please provide a solution?

img.src = URL.createObjectURL(file)

2

Answers


  1. The reason it’s not working is because the src* attribute accepts a URL, which is a String — but here you are inserting an array buffer**.

    You have to either…

    1. Convert it to a Data URL*** first.
    2. Host it somewhere and then use that hosted URL.

    Example 1: Using a Data URL

    
    
    const handleUpdateFile = (e) => {
      const file = e.target.files[0];
      if (!file) return;
    
      const reader = new FileReader();
      reader.onload = () => {
        const arrayBuffer = reader.result;
        const base64String = arrayBufferToBase64(arrayBuffer); // Convert ArrayBuffer to Base64
        const dataUrl = `data:${file.type || 'image/png'};base64,${base64String}`;
        console.log(dataUrl);
        
        
    
        
        // Options: Append it to the DOM or set an existing element's `src` to the Data URL.
        
        // Option 1: Assign to an existing element.
        document.getElementById("preview").src = dataUrl;
    
        // Option 2: Append it to the DOM.
        const img = new Image();
        img.src = dataUrl;
        document.body.appendChild(img);
      };
    
      reader.readAsArrayBuffer(file); // Read the file as ArrayBuffer
    };
    
    // Helper function to convert ArrayBuffer to Base64
    const arrayBufferToBase64 = (buffer) => {
      let binary = '';
      const bytes = new Uint8Array(buffer);
      const len = bytes.byteLength;
      for (let i = 0; i < len; i++) {
        binary += String.fromCharCode(bytes[i]);
      }
      return btoa(binary);
    };
    #container {
      display: flex;
      flex-direction: column;
    }
    
    #input {
      margin-bottom: 1.5rem;
    }
    
    #preview {
      width: 480px;
      height: 270px;
      max-width: 100%;
      border-radius: 3ch;
      overflow: clip;
      border: 1px dashed grey;
      object-fit: cover;
    }
    <div id="container" onchange="handleUpdateFile(event)">
      <input id="input" type="file" />
      <img id="preview" />
    </div>

    Example 2: Hosting it:

    const express = require('express');
    const multer = require('multer');
    const path = require('path');
    
    const app = express();
    const PORT = 3000;
    
    // Set up storage configuration with multer
    const storage = multer.diskStorage({
      destination: 'uploads/', // Folder where files are saved
      filename: (req, file, cb) => {
        cb(null, Date.now() + path.extname(file.originalname)); // Unique filename
      },
    });
    
    const upload = multer({ storage });
    
    // Serve the uploaded images statically
    app.use('/uploads', express.static('uploads'));
    
    // Endpoint to handle file upload
    app.post('/upload', upload.single('file'), (req, res) => {
      if (!req.file) {
        return res.status(400).json({ error: 'No file uploaded' });
      }
      const fileUrl = `${req.protocol}://${req.get('host')}/uploads/${req.file.filename}`;
      res.json({ fileUrl });
    });
    
    app.listen(PORT, () => {
      console.log(`Server is running at http://localhost:${PORT}`);
    });
    

    Then, on the front-end use the following:

    <img src="http://localhost:3000/uploads/123456789.jpg" />
    

    * https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img#src

    ** https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer

    *** https://developer.mozilla.org/en-US/docs/Web/URI/Schemes/data

    Login or Signup to reply.
  2. Friend, you’re using a FileReader to generate a blob when the file got from the <input> field is already blob like.

    See if this example works for you:

    const handleUpdateFile = fileEvent =>
    {
      const file = fileEvent.target.files[0];
      const url = URL.createObjectURL(file);
      const img = document.createElement('img');
      const out = document.querySelector('#myTest');
      
      img.addEventListener('load', loadEvent => URL.revokeObjectURL(loadEvent.target.src));
      img.src = url;
      
      console.clear();
      console.log('Generated URL:', url);
      
      out.replaceChildren(img);
    }
    
    // TEST \
    document
      .querySelector('#myFileSelector')
      .addEventListener('change', handleUpdateFile);
    <div>
      <input id="myFileSelector" type="file" accept="image/*" />
    </div>
    <div id="myTest"></div>

    NOTE that Object URLs are usable only at the environment that sets them (like the client used). This means the generated URL by URL.createObjectURL() is not accessible in other clients (because the generator client does not turn into a server to serve the link). In other words, if the URL is generated in Chrome, you can’t retrieve the file at Firefox with that URL.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search