1

I am trying to upload an image in angular 5 with multer using in node js. But its not doing upload.

I am using the formData to get file details in angular 5 and sending the data to backend. But its not doing upload here.

Here is the code what I have now

event-create.component.html looks like this

<div class="container col-md-10">
    <h1 class="page-header">Create Event</h1>
    <form [formGroup] = "form" (ngSubmit)="onEventSubmit()">
  <fieldset>
    <div class="form-group">
        <label for="eventname">Event Name</label>
      <div class='input-group date col-sm-6'>
        <input type="text" class="form-control" autocomplete="off" placeholder="Event Name" formControlName="eventname">
      </div>
    </div>

    <div class="form-group">
      <label for="eventimage">Event Image</label>
      <div class="input-group">
        <span class="input-group-btn">
          <span class="btn btn-default btn-file">
            Browse… <input type="file" id="eventimage" name="eventimage"  formControlName="eventimage" (change)="fileChangeEvent($event)" >

          </span>
        </span>
        <input type="text" class="form-control" readonly>
      </div>
      <img id='img-upload'/>
    </div>

    <input type="submit" class="btn btn-primary" value="Submit">

  </fieldset>
</form>
</div>

event-create.component.ts looks like this

import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { FormControlName } from '@angular/forms/src/directives/reactive_directives/form_control_name';
import { EventService } from '../event.service';
import { Response } from '@angular/http';


@Component({
  selector: 'app-event-create',
  templateUrl: './event-create.component.html',
  styleUrls: ['./event-create.component.css']
})
export class EventCreateComponent implements OnInit {

    private file_form;
  form :  FormGroup;
  message;
  messageClass;
  processing = false;
  filesToUpload: Array<File> = [];




  constructor(
    private formBuilder : FormBuilder,
    private eventService : EventService,
    ) { this.createEventForm(); }

  createEventForm() {
    this.form = this.formBuilder.group({
      eventname: ['', Validators.required],
      eventimage: [''],
    })
  }

  ngOnInit() {
  }

  onEventSubmit() {
    const event = {
      eventname : this.form.value.eventname,
      eventimage : this.file_form,
    }


    this.eventService.addNewEvent(event).subscribe( data => {
      if( !data.success ) {
        this.messageClass = 'alert alert-danger';
      }
      else {
        this.messageClass = 'alert alert-success';
      }
    });
  }


  fileChangeEvent(event) {
    let files = event.target.files;
    if(files.length > 0) {
      let file = files[0];
      let formData = new FormData();
      formData.append('eventimage', file, file.name);
      this.file_form = formData;
    }

  }

}

event.service.ts looks like this

import { Injectable } from '@angular/core';
import { Http, Headers, RequestOptions } from '@angular/http';
import { Observable } from 'rxjs';
import { HttpClientModule } from '@angular/common/http';

import { HttpClient } from "@angular/common/http";
import 'rxjs/add/operator/map';


@Injectable()
export class EventService {

  domain = 'http://localhost:8080';

  headers = new Headers({ 'Content-Type': 'application/json' });

  constructor(
   private http: Http,
    ) { }


  addNewEvent(event) {
    return this.http.post(this.domain + '/event', {headers: this.headers}, event).map(res => res.json());
  }

}

my express.js looks like this

/* ===================
   Import Node Modules
=================== */
const express = require('express');
const app = express();
const router = express.Router();

const mongoose = require('mongoose');
const config = require('./database');
const path  = require('path');
const appRoot  = require('app-root-path') ;

const event = require('./routes/event.router');
const bodyParser = require('body-parser');
const multer = require('multer');


const cors = require('cors');

const port = process.env.PORT || 8080; // Allows heroku to set port

mongoose.Promise = global.Promise;

process.env.NODE_ENV = 'production';


// Database Connection
mongoose.connect(config.uri, {
  useMongoClient: true,
}, (err) => {
  // Check if database was able to connect
  if (err) {
    console.log('Could NOT connect to database: ', err); // Return error message
  } else {
    console.log('Connected to ' + config.db); // Return success message
  }
});


app.use(cors());

//app.use(bodyParser.urlencoded({ extended: false }));

app.use(bodyParser.json());

app.use(express.static(path.join(appRoot.path, 'dist')));
app.use('/event', event);

// Serve only the static files form the dist directory
app.get('*', (req, res) => {
    res.sendFile(path.join(appRoot.path, 'dist/index.html'));
  });

// Start Server: Listen on port 8080
app.listen(port, () => {
  console.log('Listening on port ' + port + ' in ' + process.env.NODE_ENV + ' mode');
});

event.router.js looks like this

var express = require('express');
var router = express.Router();
var mongoose = require('mongoose');

const Event = require('../../model/event.model');
const multer = require('multer');
var storage = multer.diskStorage({
  destination: function (req, file, cb) {
    cb(null, './uploads/');
  },
  filename: function (req, file, cb) {
    cb(null, file.fieldname + '-' + Date.now())
  }
});

var upload = multer({ storage: storage }).single('eventimage');




/* SAVE EVENT */
//app.post('/api/image', upload.array('image', 5), (req, res, next) => {

router.post('/', function(req, res, next)  {
  upload(req, res, function(err) {
    console.log(req.file); //showing undefined
    console.log(req.files); //showing undefined
    if (err) {
        // An error occurred when uploading
        throw err;
    }
    res.json({
        sucess: true,
        message: 'Image was uploaded successfully'
    });
    // Everything went fine
  });


});

So can someone please tell me what I am doing wrong here. Any help and suggestions will be really appreciable.

Here is the screenshot from chrome dev tools.

enter image description here

I don't know why eventimage is showing as a blank object.

NewUser
  • 12,713
  • 39
  • 142
  • 236
  • Here is an good explanation about file upload in angular 5 with formData: https://stackoverflow.com/questions/47936183/angular-5-file-upload/47938117#47938117 and here is another example: https://stackoverflow.com/questions/45690051/how-to-upload-image-file-with-formgroup-value-to-api/45690203#45690203 – Gregor Doroschenko Feb 01 '18 at 10:27
  • @GregorDoroschenko I have tried that method but its still not working. – NewUser Feb 01 '18 at 11:34

1 Answers1

0
addNewEvent(event) {
    return this.http.post(this.domain + '/event', {headers: this.headers}, event).map(res => res.json());
  }

If I'm not mistaken it looks like you are just sending headers - think your parameters are in the wrong order. From the documentation:

  post(url: string, body: any, options?: RequestOptionsArgs): Observable<Response>

so your header options are coming before the body. Try this:

return this.http.post(this.domain + '/event',  event, {headers: this.headers}).map(res => res.json());
Squiggs.
  • 4,299
  • 6
  • 49
  • 89
  • I tried what you have told but its showing me error in terminal like `Error: Can't set headers after they are sent.` If I am trying to sent it without headers then it showing error like undefined where I have made `console.log(req.file);` – NewUser Feb 01 '18 at 09:36
  • can you debug what exactly is being posted? like all your request headers etc. that might help figure out what your code is sending when. see this answer: https://stackoverflow.com/questions/15603561/how-can-i-debug-a-http-post-in-chrome – Squiggs. Feb 02 '18 at 09:19
  • I have updated my question with screenshot . Please check it. – NewUser Feb 02 '18 at 09:40