2022 Web Development Bootcamp

Section 27: Handling File Uploads - Saving Those Beautiful Images

olivia_yj 2022. 9. 25. 07:33

The goals

๐Ÿ’ช๐ŸปThe Different Parts Of "Uploading Files"

โœŒ๐ŸปSelecting & Uploading Files

๐Ÿ‘๐ŸปStoring & Serving Uploaded Files

 

The Two Sides Of File Uploads

<main id="new-user">
    <form action="/profiles" method="POST">
      <div class="form-control">
        <label for="username">Username</label>
        <input type="text" id="username" name="username" required>
      </div>
      <div class="form-control">
        <label for="image">User image</label>
        <!-- <input type="file" id="image" name="image"> -->
      </div>
      <button class="btn">Save User</button>
    </form>
  </main>

When the code is like above, we get this page.

<main id="new-user">
    <form action="/profiles" method="POST">
      <div class="form-control">
        <label for="username">Username</label>
        <input type="text" id="username" name="username" required>
      </div>
      <div class="form-control">
        <label for="image">User image</label>
        <input type="file" id="image" name="image">
      </div>
      <button class="btn">Save User</button>
    </form>
  </main>

Here I put 'input' with type file, then it looks like this.

We can make this field as essential field and can set the file format also.

 

HTML attribute: accept

The accept attribute takes as its value a comma-separated list of one or more file types, or unique file type specifiers, describing which file types to allow.

The accept property is an attribute of the file <input> type. It was supported on the <form> element, but was removed in favor of file.

Because a given file type may be identified in more than one manner, it's useful to provide a thorough set of type specifiers when you need files of specific type, or use the wild card to denote a type of any format is acceptable.

For instance, there are a number of ways Microsoft Word files can be identified, so a site that accepts Word files might use an <input> like this:

<input
  type="file"
  id="docpicker"
  accept=".doc,.docx,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document" />

Whereas if you're accepting a media file, you may want to be include any format of that media type:

<input type="file" id="soundFile" accept="audio/*" />
<input type="file" id="videoFile" accept="video/*" />
<input type="file" id="imageFile" accept="image/*" />

The accept attribute doesn't validate the types of the selected files; it provides hints for browsers to guide users towards selecting the correct file types. It is still possible (in most cases) for users to toggle an option in the file chooser that makes it possible to override this and select any file they wish, and then choose incorrect file types.

Because of this, you should make sure that expected requirement is validated server-side.

 

<form method="post" enctype="multipart/form-data">
  <div>
    <label for="profile_pic">Choose file to upload</label>
    <input
      type="file"
      id="profile_pic"
      name="profile_pic"
      accept=".jpg, .jpeg, .png" />
  </div>
  <div>
    <button>Submit</button>
  </div>
</form>

 

HTML <form> enctype Attribute

Example

Send form-data encoded as "multipart/form-data":

<form action="/action_page_binary.asp" method="post" enctype="multipart/form-data">
  <label for="fname">First name:</label>
  <input type="text" id="fname" name="fname"><br><br>
  <label for="lname">Last name:</label>
  <input type="text" id="lname" name="lname"><br><br>
  <input type="submit" value="Submit">
</form>

Attribute Values

Value Description
application/x-www-form-urlencoded Default. All characters are encoded before sent (spaces are converted to "+" symbols, and special characters are converted to ASCII HEX values)
multipart/form-data This value is necessary if the user will upload a file through the form
text/plain Sends data without any encoding at all. Not recommended

 

In most cases, the default works very well, so it’s not necessary to specify an enctype. The one exception is any form where you invite file uploads. In this case, you must specify the multipart/form-data value for the enctype attribute for efficient and effective file transmission.

Multer

Multer is a node.js middleware for handling multipart/form-data, which is primarily used for uploading files. It is written on top of busboy for maximum efficiency.

Multer is a Node.js middleware for handling multipart/form-data that makes the otherwise painstaking process of uploading files in Node.js much easier.

Multer is a middleware designed to handle multipart/form-data in forms. It is similar to the popular Node.js body-parser, which is built into Express middleware for form submissions. But, Multer differs in that it supports multipart data, only processing multipart/form-data forms.

Multer does the work of body-parser by attaching the values of text fields in the req.body object. Multer also creates a new object for multiple files, either req.file or req.files, which holds information about those files. From the file object, you can pick whatever information is required to post the file to a media management API, like Cloudinary.

 

const express = require('express');
const multer = require('multer');

const upload = multer({});
const router = express.Router();

So here in our case, we wrote code like this to use as 'upload'

 

router.post('/profiles', upload.single('image') , function(req,res) {

})

When we make router, we can use any middleware in this router even as many as we can.

Usually we used function which is also kind of middleware.

So we will upload single file which has name 'image' and it will apply to all of the single request that are received by this route.

 

Where Should We Store Uploaded Files?

Databases are not supposed to store files. Databases are only for the simple resources like id, name, password etc..

So we need to send it to File system which is also called 'Hard Drive'.

 

const express = require('express');
const multer = require('multer');

const upload = multer({ dest: 'images' });
const router = express.Router();

router.get('/', function(req, res) {
  res.render('profiles');
});

router.get('/new-user', function(req, res) {
  res.render('new-user');
});

router.post('/profiles', upload.single('image') , function(req,res) {
  const uploadedImageFile = req.file;
  const userData = req.body;

  console.log(uploadedImageFile);
  console.log(userData);

  res.redirect('/');
})
module.exports = router;

And we set 'dest' which means 'destination' so if we upload the file can go to that direction.

So it's about setting specific path.

We made 'images' folder for this.

And then go back to the page and upload image file.

 

We can see that the image file successfully arrived into our folder.

But file name has been automatically generated so we need to change the name of it and it doesn't have extension so we need to modify it.

 

So for that we will write some code here,

 

const storageConfig = multer.diskStorage({
  destination: function(req, file, cb) {},
  filename:
});

cb means call back here. 

 

Multer destination

example

const multer  = require('multer')
const upload = multer({ dest: './public/data/uploads/' })
app.post('/stats', upload.single('uploaded_file'), function (req, res) {
   // req.file is the name of your file in the form above, here 'uploaded_file'
   // req.body will hold the text fields, if there were any 
   console.log(req.file, req.body)
});

 

API

File information

Each file contains the following information:

KeyDescriptionNote

fieldname Field name specified in the form  
originalname Name of the file on the user’s computer  
encoding Encoding type of the file  
mimetype Mime type of the file  
size Size of the file in bytes  
destination The folder to which the file has been saved DiskStorage
filename The name of the file within the destination DiskStorage
path The full path to the uploaded file DiskStorage
buffer A Buffer of the entire file MemoryStorage

multer(opts)

Multer accepts an options object, the most basic of which is the dest property, which tells Multer where to upload the files. In case you omit the options object, the files will be kept in memory and never written to disk.

By default, Multer will rename the files so as to avoid naming conflicts. The renaming function can be customized according to your needs.

The following are the options that can be passed to Multer.

KeyDescription

dest or storage Where to store the files
fileFilter Function to control which files are accepted
limits Limits of the uploaded data
preservePath Keep the full path of files instead of just the base name

In an average web app, only dest might be required, and configured as shown in the following example.

const upload = multer({ dest: 'uploads/' })

If you want more control over your uploads, you’ll want to use the storage option instead of dest. Multer ships with storage engines DiskStorage and MemoryStorage; More engines are available from third parties.

 

multer๋ฅผ ์‚ฌ์šฉํ•ด ์ด๋ฏธ์ง€๋ฅผ ์—…๋กœ๋“œ ๋ฐ ํผ๋ฐ์ดํ„ฐ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฒ• - ์ œ๋กœ์ดˆ ๋ธ”๋กœ๊ทธ ์ฐธ๊ณ 

๋ณดํ†ต JSON ํ˜•์‹์œผ๋กœ ๋œ ๋ฐ์ดํ„ฐ๋Š” AJAX๋กœ๋“  ํผ ํƒœ๊ทธ๋กœ๋“  ์‰ฝ๊ฒŒ ์—…๋กœ๋“œํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์ด๋ฏธ์ง€ ํŒŒ์ผ๋งŒํผ์€ ์‚ฌ๋žŒ๋“ค์˜ ๊ณจ์น˜๋ฅผ ์ฉ์ด๋Š”๋ฐ์š”. express์™€ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜๋ฉด ์‰ฝ๊ฒŒ ์ด๋ฏธ์ง€ ์—…๋กœ๋“œ๋ฅผ ๋„์™€์ฃผ๋Š” multer ๋ชจ๋“ˆ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

npm i multer

์ด์ œ ์„ค์น˜๋œ multer๋ฅผ ์‚ฌ์šฉํ•ด ์ฝ”๋”ฉ์„ ํ•ด๋ด…์‹œ๋‹ค. ์ต์Šคํ”„๋ ˆ์Šค ๋ผ์šฐํ„ฐ ๋ถ€๋ถ„์— ๋‹ค์Œ์„ ์ถ”๊ฐ€ํ•ด์ค๋‹ˆ๋‹ค.

const multer = require('multer');
// ๊ธฐํƒ€ express ์ฝ”๋“œ
const upload = multer({ dest: 'uploads/', limits: { fileSize: 5 * 1024 * 1024 } });
app.post('/up', upload.single('img'), (req, res) => {
  console.log(req.file); 
});

์ด์ œ ํผ๋ฐ์ดํ„ฐ๋‚˜ ํผ ํƒœ๊ทธ๋ฅผ ํ†ตํ•ด ์—…๋กœ๋“œํ•œ ์ด๋ฏธ์ง€๋ฅผ ์˜ฌ๋ฆฌ๋ฉด req.file๋กœ ์ •๋ณด๊ฐ€ ๋“ค์–ด์˜ค๊ณ , dest ์†์„ฑ์— ์ง€์ •ํ•ด๋‘” ๊ฒฝ๋กœ์— ์ด๋ฏธ์ง€๊ฐ€ ์ €์žฅ๋ฉ๋‹ˆ๋‹ค. limits ์†์„ฑ์€ ์„ ํƒ ์‚ฌํ•ญ์ธ๋ฐ ์—ฌ๋Ÿฌ ๊ฐ€์ง€ ์ œํ•œ์„ ๊ฑธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์œ„์—์„œ๋Š” ํŒŒ์ผ ์‚ฌ์ด์ฆˆ๋ฅผ 5MB๋กœ ์ œํ•œํ–ˆ์Šต๋‹ˆ๋‹ค. ํผ๋ฐ์ดํ„ฐ๋กœ ์—…๋กœ๋“œํ•˜๋Š” ๊ฐ•์ขŒ๋Š” ์—ฌ๊ธฐ๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”. upload.single('img') ๋ฏธ๋“ค์›จ์–ด๋ฅผ ๋ผ์šฐํ„ฐ ์ฝœ๋ฐฑํ•จ์ˆ˜ ์ „์— ๋ผ์›Œ๋„ฃ์—ˆ๋Š”๋ฐ์š”. ํผ๋ฐ์ดํ„ฐ์˜ ์†์„ฑ๋ช…์ด img์ด๊ฑฐ๋‚˜ ํผ ํƒœ๊ทธ ์ธํ’‹์˜ name์ด img์ธ ํŒŒ์ผ ํ•˜๋‚˜๋ฅผ ๋ฐ›๊ฒ ๋‹ค๋Š” ๋œป์ž…๋‹ˆ๋‹ค. ์ด๋ฏธ์ง€๊ฐ€ ์•„๋‹Œ ๋‚˜๋จธ์ง€ ๋ฐ์ดํ„ฐ๋Š” ๊ทธ๋Œ€๋กœ req.body์— ๋“ค์–ด์˜ต๋‹ˆ๋‹ค.

๋งŒ์•ฝ ์ด๋ฏธ์ง€๋ฅผ ํ•˜๋‚˜๊ฐ€ ์•„๋‹Œ ์—ฌ๋Ÿฌ ๊ฐœ๋ฅผ ๋ฐ›๊ณ  ์‹ถ๋‹ค ํ•˜๋ฉด upload.array('ํ‚ค', ์ตœ๋Œ€ํŒŒ์ผ๊ฐœ์ˆ˜) ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค. req.file ๋Œ€์‹  req.files์— ์ •๋ณด๊ฐ€ ๋‹ด๊น๋‹ˆ๋‹ค.

app.post('/up', upload.array('img'), (req, res) => {
  console.log(req.files);
});

๋งŒ์•ฝ ์—ฌ๋Ÿฌ ๊ฐœ์˜ ํ‚ค๋กœ ์ด๋ฏธ์ง€๋ฅผ ์˜ฌ๋ ธ๋‹ค๋ฉด upload.fields๋ฅผ ์จ์•ผ ํ•ฉ๋‹ˆ๋‹ค(์ด์™ธ์— upload.none๋„ ์žˆ์Šต๋‹ˆ๋‹ค). ์‚ฌ์šฉํ•œ ํ‚ค๋“ค์„ ๋ฐฐ์—ด ์•ˆ์— ๋„ฃ์–ด์ฃผ๋ฉด ๋ฉ๋‹ˆ๋‹ค.

app.post('/up', upload.fields([{ name: 'img' }, { name: 'photos' }]), (req, res) => {
  console.log(req.files);
});

๋ฌธ์ œ๋Š” uploads ํด๋”์— ๋ญ”๊ฐ€ ์ƒ์„ฑ์ด ๋˜๊ธด ํ•˜๋Š”๋ฐ ์ด๋ฆ„๋„ ce243370b74107493fea0743d249a176์ฒ˜๋Ÿผ ์ด์ƒํ•˜๊ฒŒ ๋ฐ”๋€Œ์–ด์žˆ๊ณ  ํ™•์žฅ์ž๋„ ๋ถ™์–ด ์žˆ์ง€ ์•Š์•„ ์“ธ ์ˆ˜๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ์‚ฌ์‹ค ์ด๊ฒƒ์€ ๋ณด์•ˆ์ƒ ์˜๋„๋œ ๊ฒƒ์ด์ง€๋งŒ ์ง€๊ธˆ์€ ๋ถˆํŽธํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ด๋ฆ„์ด ์›๋ž˜๋Œ€๋กœ ๋‚˜์˜ค๊ฒŒ ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. dest ์†์„ฑ ๋Œ€์‹  storage ์†์„ฑ์„ ์‚ฌ์šฉํ•ด upload ๋ณ€์ˆ˜์— ๋„ฃ์–ด์ฃผ๋ฉด ๋ฉ๋‹ˆ๋‹ค.

const upload = multer({
  storage: multer.diskStorage({
    destination: function (req, file, cb) {
      cb(null, 'uploads/');
    },
    filename: function (req, file, cb) {
      cb(null, file.originalname);
    }
  }),
});

๋„ค. ์กฐ๊ธˆ ๋ณต์žกํ•ด์กŒ๊ธด ํ•˜์ง€๋งŒ ์œ„์˜ ์ฝ”๋“œ๋ฅผ ๋ณด์‹œ๋ฉด ์ €์žฅ๋  ๊ฒฝ๋กœ(destination)๊ณผ ํŒŒ์ผ๋ช…(filename)์„ ์กฐ์ž‘ํ•˜๊ณ  ์žˆ์Œ์„ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด์ œ ๋‹ค์‹œ ํŒŒ์ผ์„ ์˜ฌ๋ฆฌ๋ฉด ์›๋ณธ ํŒŒ์ผ๋ช… ๊ทธ๋Œ€๋กœ ์˜ฌ๋ผ๊ฐ‘๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ํŒŒ์ผ๋ช…์ด ์ค‘๋ณต๋˜๋Š” ๊ฒฝ์šฐ ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธธ ์ˆ˜ ์žˆ์ฃ . ํŒŒ์ผ๋ช…์„ ํƒ€์ž„์Šคํƒฌํ”„๋กœ ํ•ด์„œ ์ค‘๋ณต๋˜์ง€ ์•Š๊ฒŒ ํ•ด๋ด…์‹œ๋‹ค.

const path = require('path');
const upload = multer({
  storage: multer.diskStorage({
    destination: function (req, file, cb) {
      cb(null, 'uploads/');
    },
    filename: function (req, file, cb) {
      cb(null, new Date().valueOf() + path.extname(file.originalname));
    }
  }),
});

์œ„์™€ ๊ฐ™์ด ํ•˜์‹œ๋ฉด ํƒ€์ž„์Šคํƒฌํ”„.ํ™•์žฅ์ž ํ˜•์‹์œผ๋กœ ํŒŒ์ผ๋ช…์ด ์ง€์ •๋ฉ๋‹ˆ๋‹ค.

์ง€๊ธˆ๊นŒ์ง€๋Š” ์‹ค์ œ ๋””์Šคํฌ์— ํŒŒ์ผ์„ ์—…๋กœ๋“œํ–ˆ๋Š”๋ฐ์š”. S3๊ฐ™์€ ๊ณณ์— ์—…๋กœ๋“œํ•˜์‹œ๋Š” ๋ถ„๋“ค๋„ ์žˆ์„ ๊ฒ๋‹ˆ๋‹ค. S3์— ์—…๋กœ๋“œํ•˜๋Š” ๋ฐฉ์‹์€ ํฌ๊ฒŒ ๋‘ ๊ฐ€์ง€๊ฐ€ ์žˆ๋Š”๋ฐ์š”. ๋””์Šคํฌ์— ์žˆ๋Š” ํŒŒ์ผ์„ ์—…๋กœ๋“œํ•˜๊ฑฐ๋‚˜, ํŒŒ์ผ ๋ฒ„ํผ(๋ฉ”๋ชจ๋ฆฌ์— ์ €์žฅ)๋ฅผ ์—…๋กœ๋“œํ•˜๋Š” ๊ฒ๋‹ˆ๋‹ค. ํŒŒ์ผ์„ S3์— ์—…๋กœ๋“œํ•œ ํ›„์—๋Š” ๋‚จ์•„์žˆ๋Š” ํŒŒ์ผ์„ ์ง€์›Œ์ค˜์•ผ ํ•˜๋Š”๋ฐ ์ด๊ฒŒ ๋ฒˆ๊ฑฐ๋กญ์ฃ . ๊ทธ๋ž˜์„œ ์ฒ˜์Œ๋ถ€ํ„ฐ ๋ฉ”๋ชจ๋ฆฌ์— ํŒŒ์ผ์„ ๋ฒ„ํผ ํ˜•์‹์œผ๋กœ ์ €์žฅํ•˜๊ณ , ๊ทธ๊ฒƒ์„ ์—…๋กœ๋“œํ•˜๋Š” ๊ฒ๋‹ˆ๋‹ค.

const upload = multer({
  storage: multer.memoryStorage(),
});

๋ฉ”๋ชจ๋ฆฌ์Šคํ† ๋ฆฌ์ง€๋ฅผ ์“ธ ๊ฒฝ์šฐ๋Š” req.file์ด๋‚˜ req.files ์•ˆ์˜ ํŒŒ์ผ ๋ฐ์ดํ„ฐ(๊ฐ์ฒด)์—, ๋””์Šคํฌ์Šคํ† ๋ฆฌ์ง€ ์ „์šฉ ์†์„ฑ์ธ destination, filename, path ๋Œ€์‹  buffer๋ผ๋Š” ์†์„ฑ์ด ์ƒˆ๋กœ ์ƒ๊ธฐ๊ณ  ๊ทธ ๊ฐ’์œผ๋กœ ๋ฒ„ํผ๋“ค์ด ์ €์žฅ๋ฉ๋‹ˆ๋‹ค. ์ด ๋ฒ„ํผ๋ฅผ ์‚ฌ์šฉํ•ด์„œ S3์— ๋ฒ„ํผ๋กœ ์—…๋กœ๋“œํ•˜์‹œ๋ฉด ๋ฉ๋‹ˆ๋‹ค. ์ด ๋ฐฉ์‹์˜ ๋‹จ์ ์€ ํŒŒ์ผ์ด ์—ฌ๋Ÿฌ ๊ฐœ๊ณ , ์šฉ๋Ÿ‰์ด ๋„ˆ๋ฌด ํฌ๋ฉด ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ์ดˆ๊ณผํ•ด์„œ ์„œ๋ฒ„๊ฐ€ ๋ฉˆ์ถฐ๋ฒ„๋ฆด ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ณดํ†ต์€ ๊ทธ๋Ÿด ์ผ์€ ์—†๊ฒ ์ง€๋งŒ ๊ทธ๋Ÿด ์ˆ˜๋„ ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ์•„๋‘์„ธ์š”. ์ด๋Ÿฌํ•œ ๋ฌธ์ œ๊ฐ€ ๊ฑฑ์ •๋˜๊ณ , ๋ฒ„ํผ๋ฅผ ๋‹ค๋ฃจ๋Š” ๊ฒŒ ์–ด๋ ต๋‹ค๋ฉด multer-s3 ํŒจํ‚ค์ง€๋ฅผ ๊ณ ๋ คํ•ด๋ณด์„ธ์š”.

 

const express = require('express');
const multer = require('multer');

const storageConfig = multer.diskStorage({
  destination: function(req, file, cb) {
    cb(null, 'images');
  },
  filename: function(req, file, cb) {
    cb(null, Date.now() + '-' + file.originalname);
  }
});

const upload = multer({ storage: storageConfig });
const router = express.Router();

We have database connection like this,

 

And we wrote the code like this.

Now let's try to insert data into db.

 

We can see that it arrived well

Now let's move on to the next step.

How can we show the list of our users on our start page?

 

Go to the main page route.

router.get('/', async function(req, res) {
  const users = await db.getDb().collection('users').find().toArray();
  res.render('profiles', {users});
});

FIx the code like this.

And since we gave all the data we fetch from database as 'users' to 'profiles' file. We can utillze data there.

 

<body>
  <main>
    <section id="user-controls">
      <a class="btn" href="/new-user">Add a New User</a>
    </section>
    <section id="user-profiles">
      <ul>
        <% for (const user of users) { %>
          <li class="user-item">
            <article>
              <img src="<%= user.imagePath %>" alt="The image of the user.">
              <h2><%= user.name %></h2>
            </article>
          </li>
        <% } %>
      </ul>
    </section>
  </main>
</body>

 

So it we try to fetch the data like this, would it work well?

No

If we go to our website after writing this code, we will get this error.

 

It couldn't find the file

If the user can control our files and data it would be quite serious issue for security.

So in app.js,

app.use(express.urlencoded({ extended: false }));
app.use(express.static('public'));
app.use(express.static('images'));

We added images folder to provide to users so they also can see our files.

But they can't do anything with it. Just can see our files.

And we can put condition here.

app.use('/images', express.static('images'));

So only when the user enter into our webpage with /images they can see our resources

 

Now let's check how to make preview of profile picture when we upload in frontend

 

So for this we input the script in our html file.

  <link rel="stylesheet" href="/styles/base.css">
  <link rel="stylesheet" href="/styles/profiles.css">
  <script src="/scripts/file-preview.js" defer></script>
</head>
<body>
  <main id="new-user">
    <form action="/profiles" method="POST" enctype="multipart/form-data">
      <div class="form-control">
        <label for="username">Username</label>
        <input type="text" id="username" name="username" required>
      </div>
      <div class="form-control">
        <img id="image-preview" alt="Your picked image.">
        <label for="image">User image</label>
        <input type="file" id="image" name="image" required accept="image/jpg, image/png">
      </div>
      <button class="btn">Save User</button>
    </form>
  </main>
</body>

This is new-user file.

const filePickerElement = document.getElementById('image');
const imagePreviewElement = document.getElementById('image-preview');

function showPreview() {
  const files = filePickerElement.files;
  if (!files || files.length === 0) {
    imagePreviewElement.style.display = 'none';
    return;
  }

  const pickedFile = files[0];

  imagePreviewElement.src = URL.createObjectURL(pickedFile);
  imagePreviewElement.style.display = 'block';
}

filePickerElement.addEventListener('change', showPreview);

And this is file-preview.

We get to 'filePickerElement' and use 'files' property.

It's files not 'file', because theoritically you can use this for multi file. 

And we wrote code here that if file doesn't exist or the length of file is zero which means equal to that we don't have file, then we will just hide the preview and return which means end.

And then we will make variable 'pickedFile' and its first item which means only item will be taken.

And we used URL which is JavaScript built-in item, and createObjectURL which is also the same to generate the url of this image source.

 

 

 

 

Souces

https://www.w3schools.com/tags/att_form_enctype.asp

 

HTML form enctype Attribute

W3Schools offers free online tutorials, references and exercises in all the major languages of the web. Covering popular subjects like HTML, CSS, JavaScript, Python, SQL, Java, and many, many more.

www.w3schools.com

https://html.com/attributes/form-enctype/

 

Attribute for ENCTYPE = "multipart/form-data" | "application/x-www-form-urlencoded" | "text/plain"

The enctype attribute lets you specify an encoding type for your form.

html.com

https://www.npmjs.com/package/multer

 

multer

Middleware for handling `multipart/form-data`.. Latest version: 1.4.5-lts.1, last published: 4 months ago. Start using multer in your project by running `npm i multer`. There are 3447 other projects in the npm registry using multer.

www.npmjs.com

https://expressjs.com/en/resources/middleware/multer.html

 

Express multer middleware

Multer Multer is a node.js middleware for handling multipart/form-data, which is primarily used for uploading files. It is written on top of busboy for maximum efficiency. NOTE: Multer will not process any form which is not multipart (multipart/form-data).

expressjs.com

https://www.zerocho.com/category/NodeJS/post/5950a6c4f7934c001894ea83

 

https://www.zerocho.com/category/NodeJS/post/5950a6c4f7934c001894ea83

 

www.zerocho.com

https://wayhome25.github.io/nodejs/2017/02/21/nodejs-15-file-upload/

 

nodejs ํŒŒ์ผ ์—…๋กœ๋“œ - multer ๋ชจ๋“ˆ์‚ฌ์šฉ · ์ดˆ๋ณด๋ชฝํ‚ค์˜ ๊ฐœ๋ฐœ๊ณต๋ถ€๋กœ๊ทธ

multer ๋ชจ๋“ˆ์„ ํ†ตํ•ด์„œ post๋กœ ์ „์†ก๋œ ํŒŒ์ผ์˜ ์ €์žฅ๊ฒฝ๋กœ์™€ ํŒŒ์ผ๋ช… ๋“ฑ์„ ์ฒ˜๋ฆฌํ•œ๋‹ค.

wayhome25.github.io

https://victorydntmd.tistory.com/39

 

[Node.js] ํŒŒ์ผ ์—…๋กœ๋“œ ( multer ๋ชจ๋“ˆ )

2019. 07. 21 ์ˆ˜์ • ์ด๋ฒˆ ๊ธ€์—์„œ๋Š” ํŒŒ์ผ์„ ์—…๋กœ๋“œํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์•Œ์•„๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ๊ฐœ๋ฐœํ™˜๊ฒฝ express-generator 4.16.1 multer 1.4.2 1. ์ค€๋น„์ž‘์—… 1) npm ์„ค์น˜ body-parser ๋ชจ๋“ˆ๊ณผ multer ๋ชจ๋“ˆ์„ ์‚ฌ์šฉํ•ด์„œ ํŒŒ..

victorydntmd.tistory.com