How to upload javascript

How to upload a file using XMLHttpRequest (XHR) and Node.js

File upload is the most common functionality in modern web applications. Many applications allow users to upload an avatar or an attachment to perform some backend tasks. Writing the code to upload a file asynchronously to a server looks like a challenging task.

In this article, I’ll explain how to build an HTML form, send the selected files to the server with JavaScript, and process the upload file in Node.js.

Let us start building a simple HTML form with two elements: a tag to allow the user to select a file from the local computer and a tag to submit the form. Here is what it looks like:

form method="POST" enctype="multipart/form-data"> input type="file" name="file"> button type="submit" role="button">Upload Filebutton> form> 

Now, if you click the submit button, the form is just posted to itself as the action attribute is not defined. We want to ensure that when the form is submitted, the selected file is uploaded to the server asynchronously (without refreshing the page) using the JavaScript XHR object. Let us create a new file called upload.js and add a reference to it in your HTML file:

script src="upload.js"> script> 

Next, define two variables. The URL where your want to post the form data and the DOM element for the form:

// define URL and for element const url = "http://localhost:3000/upload-avatar" const form = document.querySelector('form') 

Next, add an event listener to the form to capture the form submission event. Also, make sure that the default action is prevented from firing:

// add event listener form.addEventListener('submit', e =>  // disable default action e.preventDefault() // . >) 
// collect files const files = document.querySelector('[name=file]').files const formData = new FormData() formData.append('avatar', files[0]) // . 

Finally, use the built-in XHR object to POST the data to the URL we defined above and print the response on the console:

// post form data const xhr = new XMLHttpRequest() xhr.responseType = 'json' // log response xhr.onload = () =>  console.log(xhr.response) > // create and send the reqeust xhr.open('POST', url) xhr.send(formData) 
// define URL and for element const url = '/upload-avatar' const form = document.querySelector('form') // add event listener form.addEventListener('submit', e =>  // disable default action e.preventDefault() // collect files const files = document.querySelector('[name=file]').files const formData = new FormData() formData.append('avatar', files[0]) // post form data const xhr = new XMLHttpRequest() // log response xhr.onload = () =>  console.log(xhr.responseText) > // create and send the reqeust xhr.open('POST', url) xhr.send(formData) >) 

The response returned by the Node.js API is a JSON object. Right now, we are only printing the response to the console. Take a look at this guide to learn about several ways to handle the JSON response in XHR.

For handling the file upload on the server-side through Node.js and Express, I’ve already written a detailed article. I won’t go into detail on how to set up the Node.js application and install all required packages. Please check the tutorial to learn all these things. The tutorial uses the express-fileupload middleware to handle multipart/form-data requests, extract the files if available, and make them available under the req.files property. You can install express-fileupload in your project by typing the following command:

$ npm install express-fileupload --save 

Next, add the following Express route to process and save the file submitted by the above JavaScript code:

app.post('/upload-avatar', async (req, res) =>  try  if (!req.files)  res.send( status: false, message: 'No file uploaded' >) > else  // use the name of the input field (i.e. "avatar") // to retrieve the uploaded file let avatar = req.files.avatar // use the mv() method to place the file in // upload directory (i.e. "uploads") avatar.mv('./uploads/' + avatar.name) //send response res.send( status: true, message: 'File is uploaded' >) > > catch (err)  res.status(500).send(err) > >) 

The above example explains how to upload a single file in JavaScript. What if you want to upload multiple files at once? No worries. With a few changes, we can adjust the above code to support multiple files upload. First of all, update the tag to allow the user to select multiple files:

input type="file" name="file" multiple> 
const url = "http://localhost:3000/upload-photos" 
Array.from(files).forEach(file =>  formData.append('photos', file) >) 
app.post('/upload-photos', async (req, res) =>  try  if (!req.files)  res.send( status: false, message: 'No file uploaded' >) > else  let data = [] //loop all files _.forEach(_.keysIn(req.files.photos), key =>  let photo = req.files.photos[key] //move photo to uploads directory photo.mv('./uploads/' + photo.name) >) //return response res.send( status: true, message: 'Files are uploaded' >) > > catch (err)  res.status(500).send(err) > >) 

That’s all folks. In this tutorial, you have learned how to upload a file using JavaScript built-in XMLHttpRequest object and Node.js on the server side. We looked at both single file uploads as well as multiple files uploaded at once. The aim of this article was to explain the basic steps required to successfully upload a file in JavaScript and Node.js. For a real-world application running on the production server, there should be some validation steps. The user should be shown an error if they select the wrong type of file or the file size exceeds the allowed limit. XMLHttpRequest also provides events to track file download and upload progress. Check out this guide to learn more about it. Read this guide to learn how to handle files upload through Fetch API, a modern alternative to XHR. ✌️ Like this article? Follow me on Twitter and LinkedIn. You can also subscribe to RSS Feed.

You might also like.

Источник

How to Upload Files with JavaScript

Austin Gil

Austin Gil

How to Upload Files with JavaScript

I recently published a tutorial showing how to upload files with HTML. That’s great, but it’s a bit limited to using the native browser form behavior, which causes the page to refresh.

In this tutorial, I want to show you how to do the same thing with JavaScript to avoid the page refresh. That way, you can have the same functionality, but with better user experience.

How to Set Up an Event Handler

Let’s say you have an HTML form that looks like this:

With HTML, to access a file on the user’s device, we have to use an with the “file” type . And in order to create the HTTP request to upload the file, we have to use a element.

When dealing with JavaScript, the first part is still true. We still need the file input to access the files on the device. But browsers have a Fetch API that we can use to make HTTP requests without forms.

I still like to include a form because:

  1. Progressive enhancement: If JavaScript fails for whatever reason, the HTML form will still work.
  2. I’m lazy: The form will actually make my work easier later on, as we’ll see.

With that in mind, for JavaScript to submit this form, I’ll set up a “submit” event handler.

const form = document.querySelector('form'); form.addEventListener('submit', handleSubmit); /** @param event */ function handleSubmit(event) < // The rest of the logic will go here. >

Throughout the rest of this article, we’ll only be looking at the logic within the event handler function, handleSubmit .

How to Prepare the HTTP Request

The first thing I need to do in this submit handler is call the event’s preventDefault method to stop the browser from reloading the page to submit the form. I like to put this at the end of the event handler so that if there is an exception thrown within the body of this function, preventDefault will not be called, and the browser will fall back to the default behavior.

/** @param event */ function handleSubmit(event) < // Any JS that could fail goes here event.preventDefault(); >

Next, we’ll want to construct the HTTP request using the Fetch API. The Fetch API expects the first argument to be a URL, and a second, optional argument as an Object.

We can get the URL from the form’s action property. It’s available on any form DOM node which we can access using the event’s currentTarget property. If the action is not defined in the HTML, it will default to the browser’s current URL.

/** @param event */ function handleSubmit(event)

Relying on the HTML to define the URL makes it more declarative, keeps our event handler reusable, and our JavaScript bundles smaller. It also maintains functionality if the JavaScript fails.

By default, Fetch sends HTTP requests using the GET method, but to upload a file, we need to use a POST method. We can change the method using fetch ‘s optional second argument. I’ll create a variable for that object and assign the method property, but once again, I’ll grab the value from the form’s method attribute in the HTML.

const url = new URL(form.action); /** @type [1]> */ const fetchOptions = < method: form.method, >; fetch(url, fetchOptions);

Now the only missing piece is actually including the payload in the body of the request.

How to Add the Request Body

If you’ve ever created a Fetch request in the past, you may have included the body as a JSON string or a URLSearchParams object. Unfortunately, neither of those will work to send a file, as they don’t have access to the binary file contents.

Fortunately, there is the FormData browser API. We can use it to construct the request body from the form DOM node. And conveniently, when we do so, it even sets the request’s Content-Type header to multipart/form-data – also a necessary step to transmit the binary data.

const url = new URL(form.action); const formData = new FormData(form); /** @type [1]> */ const fetchOptions = < method: form.method, body: formData, >; fetch(url, fetchOptions);

That’s really the bare minimum needed to upload files with JavaScript. Let’s do a little recap:

  1. Access to the file system using a file type input.
  2. Construct an HTTP request using the Fetch (or XMLHttpRequest ) API.
  3. Set the request method to POST .
  4. Include the file in the request body.
  5. Set the HTTP Content-Type header to multipart/form-data .

Today we looked at a convenient way of doing that, using an HTML form element with a submit event handler, and using a FormData object in the body of the request. The current handleSumit function should look like this:

/** @param event */ function handleSubmit(event) < const url = new URL(form.action); const formData = new FormData(form); /** @type [1]> */ const fetchOptions = < method: form.method, body: formData, >; fetch(url, fetchOptions); event.preventDefault(); >

Unfortunately, the current submit handler is not very reusable. Every request will include a body set to a FormData object and a “ Content-Type ” header set to multipart/form-data . This is too brittle. Bodies are not allowed in GET requests, and we may want to support different content types in other POST requests.

How to Make it Reusable

We can make our code more robust to handle GET and POST requests, and send the appropriate Content-Type header. We’ll do so by creating a URLSearchParams object in addition to the FormData , and running some logic based on whether the request method should be POST or GET . I’ll try to lay out the logic below:

Is the request using a POST method?

— Yes: is the form’s enctype attribute multipart/form-data ?

— — Yes: set the body of the request to the FormData object. The browser will automatically set the “ Content-Type ” header to multipart/form-data .

— — No: set the body of the request to the URLSearchParams object. The browser will automatically set the “ Content-Type ” header to application/x-www-form-urlencoded .

— No: We can assume it’s a GET request. Modify the URL to include the data as query string parameters.

The refactored solution looks like:

/** @param event */ function handleSubmit(event) < /** @type */ const form = event.currentTarget; const url = new URL(form.action); const formData = new FormData(form); const searchParams = new URLSearchParams(formData); /** @type [1]> */ const fetchOptions = < method: form.method, >; if (form.method.toLowerCase() === 'post') < if (form.enctype === 'multipart/form-data') < fetchOptions.body = formData; >else < fetchOptions.body = searchParams; >> else < url.search = searchParams; >fetch(url, fetchOptions); event.preventDefault(); >

I really like this solution for a number of reasons:

  • It can be used for any form.
  • It relies on the underlying HTML as the declarative source of configuration.
  • The HTTP request behaves the same as with an HTML form. This follows the principle of progressive enhancement, so file upload works the same when JavaScript is working properly or when it fails.

Thank you so much for reading. I hope you found this useful. If you liked this article, and want to support me, the best ways to do so are to share it, sign up for my newsletter, and follow me on Twitter.

Источник

Читайте также:  Php regexp не пробел
Оцените статью