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

I am looking for an image search API that supports JSONP so that users can easily search for images on my website

I am currently in the process of creating a blog platform. My goal is to allow users to input keywords on my site and search for images directly within the website. This way, I can easily retrieve the URL of the desired image. ...

Oops! It seems like there was an issue trying to access properties that are undefined while reading 'pipe' in Angular12

I encountered an issue when trying to send an AJAX request, displaying the following error message: ERROR TypeError: Cannot read properties of undefined (reading 'pipe') This error occurred in the ajax-loader.interceptor.ts class export class A ...

How can I bypass express csurf dynamically depending on the form data provided?

Is there a way to allow a third party to send form data via POST to my website without being subject to CSRF verification, while still requiring CSRF protection when the user submits the form? The goal is for the server to process the data provided by the ...

Installing external Javascript libraries on Parse cloud code can be done by following these steps

Currently, I have integrated these JavaScript libraries into my Parse cloud code. var request = require('request'); var fs = require('fs'); var Twit = require('twit'); However, the code refuses to compile if these libraries ...

The $ionicPopup is not being recognized by the $scope

I am facing an issue with creating a dynamic popup where images change opacity when clicked. It currently works fine outside of a function, but I need to implement it within a function. Below is my controller code: $scope.imgIds = ['0', ...

The variable in my scope is not reflecting the changes in the HTML view

Here is my code for handling file attachments in AngularJS: $scope.attachments = []; $scope.uploadFile = function(files){ for(var i=0; i<files.length; i++){ $scope.attachments.push(files[i]); console.log($scope.attachments.length); } } ...

Is it possible to execute PHP without using Ajax when clicking on a Font Awesome icon?

So, besides using Ajax, is there another solution to achieve the same result? Can a font-awesome icon be turned into a button without Ajax? In case you're unfamiliar with what I mean by a font-awesome icon, here's an example: <i id="like1" on ...

Designing a Custom Wordpress Extension and Integrating External Scripts

As I dive into the world of WordPress plugin development, I'm seeking guidance from the codex to enhance my skills. Currently, I have a basic plugin that loads a javascript file from a CDN and is supposed to display tooltips. However, I'm facing ...

Issue occurred: The error "Undefined offset 1" was encountered while trying to upload a file via

Every time I try to pass data into my file upload controller, I keep encountering an error message that says undefined offset: 1. function TestFileUpload() { $i=0; if(!isset($_FILES[$i]) ) { echo "No file is being uploaded"; } el ...

When attempting to trigger an error, the unit test will fail to pass

I am relatively new to Mocha, Chai, and Unit Testing. I'm currently attempting to create a basic test to verify the presence of Authorization headers in the request that passes through my middleware function. Despite trying various approaches such as ...

Ways to control the number of boxes that are checked

I am currently working on a script to restrict the number of checkboxes that can be checked, but I am encountering an issue where the script is disabling all checkboxes on the page. Is there a way to only disable a specific checkbox within a certain div? ...

Find out if OpenAI's chat completion feature will trigger a function call or generate a message

In my NestJS application, I have integrated a chat feature that utilizes the openai createChatCompletion API to produce responses based on user input and send them back to the client in real-time. Now, with the introduction of function calls in the openai ...

Extract specific index from a JSON array

I'm a beginner in Jquery and javascript, I am using ajax to upload an image and trying to fetch the image url. However, I keep encountering errors every time I try. Can someone assist me with this? Thank you! Here is the error message I received: Un ...

Angular does not delay for promises to settle

Issue I am facing is related to Angular not waiting for promises to be resolved. The console inspection reveals that the provider and skills objects are not retrieved before the promises are returned. I have included the key parts of the code below. The s ...

Establishing the NumbroJS cultural settings

I have been attempting to modify numbro's culture. I initially tried the straightforward method, but encountered an error: Unknown culture : ' + code numbro.culture('fr-FR'); My attempt looked like this: const br = require('numb ...

Experience the power of CanJS Observable data objects with the added feature of

When working with canJS Observable, I encountered an issue where I cannot use dots in object keys because canJS interprets them as nesting. For example, if I try to create a new observable like this: var obs = new can.Observe( { "div.test-class": { "color ...

Struggling to align the image elements accurately

I am aiming to create a layout similar to the image displayed below. To be more specific, my goal is to scatter smiley faces randomly within a 500px area while also having a border on the right side of the area. However, with the current code I'm us ...

What is the best way to access the inputName element using the ng-messages directive?

Is there a way to trigger error messages without knowing the input name? Take a look at the code snippet below: <input class="form-control" id="{{field.field_id}}" set-name="{{field.field_id}}" type="text" ...

In relation to User Interface: Analyzing target tracking and studying the flow of time

Is there a way to track mouse cursor movements, button clicks, and click times to an external database using only CSS, HTML5, and Javascript? I am curious about the possibility of conducting usability studies in this manner. ...

Implement a CSS style for all upcoming elements

I'm currently developing a Chrome extension tailored for my personal needs. I am looking to implement a CSS rule that will be applied to all elements within a certain class, even if they are dynamically generated after the execution of my extension&ap ...