What is the best method for uploading and saving a file using AngularJS and ExpressJS together?

I am using a library for AngularJS called angular-file-upload. Despite successfully setting it up and getting image uploads to work, I am facing an issue with passing the file to the server side (express js).

Jade:

input.form-input(ng-model="userAvatarFile" ng-file-select="onFileSelect($files)" name="userAvatarFile" type="file")

This is the AngularJS code snippet:

$scope.onFileSelect = function($files) {

    console.log($files);

    for (var i = 0; i < $files.length; i++) {
        var file = $files[i];
        $scope.upload = $upload.upload({
            url: '/api/user/upload', 
            method: 'POST',
            data: {myObj: $scope.userAvatarFile},
            file: file, 
        }).progress(function(evt) {
            console.log('percent: ' + parseInt(100.0 * evt.loaded / evt.total));
        }).success(function(data, status, headers, config) {
            console.log(data);
        });
    }
};

And here's the express code:

exports.upload = function(req, res) {
  console.log(req.body);
  console.log(req.files);
};

However, when checking the console output in express, it always shows:

 {}
 undefined

Any suggestions on what might be causing this issue?

Answer №1

The Multipart middleware functionality was eliminated in Connect version 3.0. To replace it, Connect suggests using either connect-multiparty or connect-busboy. In my opinion, connect-busboy is the better option. Here's how you can implement it:

(Remember to execute

npm install --save connect-busboy
)

// Initial file setup remains constant for all other instances
var express = require('express'),
    busboy  = require('connect-busboy');

app.use(busboy({ immediate: true }));

// File route
exports.upload = function (req, res) {
    req.busboy.on('file', function (fieldname, file, filename) {
        // fieldname will be 'file', file will represent the file itself (in binary format), and filename contains the name of the file
    });
    req.busboy.on('field', function (key, value) {
        // key will be 'myObj', while value will be $scope.userAvatarFile
    });
};

If you need to store the image in a file, follow these steps:

exports.upload = function (req, res) {
    req.busboy.on('file', function (fieldname, file, filename) {
        // saveTo indicates the temporary path
        var saveTo = path.join(os.tmpDir(), path.basename(fieldname));
        file.pipe(fs.createWriteStream(saveTo));

        // Further actions with saveTo
    });
};

Nevertheless, this method poses security risks (like saving data on the disk, hence why req.files is no longer available). Majority of libraries that handle files (e.g., Cloudinary) provide a WriteStream alternative. Below is an illustration with Cloudinary:

exports.upload = function (req, res) {
    req.busboy.on('file', function (fieldname, file, filename) {
        var stream = cloudinary.uploader.upload_stream(function(result) { console.log(result); });

        // Initially, you could use file.pipe(stream), but Cloudinary's stream isn't an authentic WriteStream; thus, the following approach also functions well:

        file.on('data', stream.write);
        file.on('end', stream.end);
    });
};

By the way, I adopted your code, tested it, and it performs effectively. Reach out if any issues arise. I faced a similar concern last week, so I delved into the matter.

Answer №2

tgkokk demonstrated an example using Cloudinary that is no longer functional with the latest version of Cloudinary, v1.1.1. The upload_stream method has been updated by Cloudinary to now return a Transform stream object. Instead of manually adding events to on('data') and on('end'), it is recommended to use 'pipe' as shown below.

Learn more about Cloudinary version 1.1 changes here.

exports.upload = function (req, res) {
    req.busboy.on('file', function (fieldname, file, filename) {
        var stream = cloudinary.uploader.upload_stream(function(result) {    
            console.log(result); 
        });

        // pipe usage
        file.pipe(stream);
    });
};

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

How can I include gte, lte, etc. in a URL query parameter?

Is it possible to pass queries like $gte, $lte in the URL parameter using Node/Express/Mongoose? I am currently developing a dashboard tool that requires around 40 different query options (with up to 6 selectable at a time) which can be combined in variou ...

Tips for validating a dynamic key within a Mongoose schema

Currently working on a MEAN project and in need of validating the dynamic keys in my model... Looking to create a Schema that resembles the one below var exampleSchema = new Schema({ x: { type: String, default: '', r ...

"Step-by-step guide on using JavaScript to print a PDF file stored locally

As an illustration, I have a local PDF file with 6 pages. When using the window.print() function, only one page is displayed in print preview regardless of what is shown in the browser. Instead of just one page, all pages should be visible in print previ ...

HTML elements generated dynamically do not possess any jQuery properties

I have implemented a draggable list of Div elements using jQuery. Here is the code: <div id="external-events"> <h4>List Of Staffs</h4> <div class="external-event" data-id="1">Name</div> //Draggab ...

Error: The function react__WEBPACK_IMPORTED_MODULE_6___default.a.useState is not defined as a function

Hey there! I have been working on some ReactJS code using material-ui, but it seems like I made a mistake with the placement of function handleClickOpen() and function handleClose(). Unfortunately, now my code doesn't compile. Can you help me fix it? ...

Aggregate the properties of objects in an array into a single object using Lodash

I've been struggling to figure this out on my own, so I decided to seek advice from those with more experience. I have an array of objects called items, and I need to sum up specific properties across different objects in the array. The user can selec ...

Having trouble with the JQuery scrollTop animation? Getting the error message "Cannot read property 'top' of undefined"?

I am having trouble with my jquery animation scrollTop function. Whenever I click on <a>, it takes me to the anchor without any animation. Can someone please provide a solution for this issue? Upon running the webpage, I encountered an error message ...

Using a vanilla JS object as a prop for a child component

I have created a custom Message class in my application to handle incoming messages, which is defined in message.js. Within message.js, I've implemented two classes: Message and EventEmit. The render function in my Message class requires passing an E ...

What is the best way to load a database URL asynchronously and establish a database connection prior to the initialization of an Express

My express.js app is set up to run on AWS lambda, with the database URL stored and encrypted in Amazon KMS. To access the URL, decryption using the AWS KMS service is required. // imports import mongoose from 'mongoose'; import serverless from & ...

Encountering issues with Gzip compression in my Spring Boot 1.5.10.RELEASE project

I am currently running on Spring Boot version 1.5.10.RELEASE, but I'm facing issues with Gzip compression not working correctly. When accessing http://localhost:9000, it redirects to http://localhost:8080/api/.. My AngularJS and REST API are on dif ...

Using jQuery to toggle sliding the information above a div

I am facing an issue with my customized sliding menu. The menu slides over the image but not over the content-div, pushing it aside. I have tried to fix this problem but haven't found a solution yet. My goal is for the menu to slide over all divs and ...

Triggering an event upon selecting a dropdown option

I'm currently working on a form that includes a dropdown menu. My goal is to display specific keywords for each trip when selected from the menu (preferably below the input field, as shown in the code snippet below). .show has been set to display:non ...

Automatically switch to dark mode at specified times: A simple guide

Here is the current method for toggling themes: let themeToggler = document.getElementById('theme-toggler'); themeToggler.onclick = () => { themeToggler.classList.toggle('fa-sun'); if (themeToggler.classList.contains('f ...

How can one use C# and Selenium to send text to a hidden textarea with the attribute style="display: none;"?

I'm encountering an issue where I am unable to write in the textarea using the sendkeys function in Selenium. The specific textarea I am trying to target has an ID of 'txtSkillsTaught-Value' and is located after a script tag that seems to be ...

Exploring the depths of JavaScript JSON elements

After processing my PHP code, it generates a JSON output that contains multiple entries in the same structure. Here is an example with two entries: { "0": { "campaign_id": "31", "title": "new title", "description": "new descrip ...

Server initialization error in Node.js

I'm having trouble understanding the issue at hand: a) some users are able to start their server even with the missing module, so what is the error exactly? b) How can I go about fixing this? What I've attempted so far: rm -rf node_modules npm ...

Using AngularJS to show content based on a callback function

I'm a beginner in angular and it seems like I might be overlooking something. For the registration form, I need users to provide their location. Depending on whether they allow/support navigator.geolocation, I want to display a drop-down menu for cho ...

Encountering a node.js issue

Hi there, I keep encountering this error message. Can someone explain what it means? I'm not very skilled in coding, so I would appreciate any assistance :) Best regards logon fail: 65, sessionID: 6343803 events.js:85 throw er; // Unhandled & ...

Unable to modify array in MongoDB

When trying to locate a specific book by its Id, I encountered an issue with updating the collection's owner array. The array already contains some values, but I am unable to update it with new values as intended. Book.find({_id: "5423"}, function(e ...

angular-in-memory-web-api encounters a 404 error

I recently completed the heroes tour and now I am trying to work on something similar, but I seem to be having trouble understanding angular-in-memory-web-api. Here is a snippet of my code: clients-data.service.ts import { Injectable } from '@angular/ ...