Reputation: 27
I have a reactive (model driven) form in my application and I'm having trouble getting the form data through to mongoose. When I submit the data via http post method, I keep getting an error because the backend is receiving an empty object.
I know the backend works because when I submit a post request with Postman, I get a result status of "201 Created". I've been reading the forums and various blogs for the past few days and I'm still stumped.
Questions
Notes It may look like there are some things missing, such as the URL, and you will notice some additional fields in the form. I purposely did not include all of these for conciseness and obfuscated the actual links to my backend.
jobs.controllers.js
var mongoose = require('mongoose');
var Job = mongoose.model('Job');
module.exports.addNewJob = function(req, res){
console.log(req.body);//added to see req payload from client
Job
.create({
_id: req.body.jobid,
desc: req.body.name,
type: req.body.jobType,
location: req.body.location
},function(err, job){
if(err){
console.log("Error creating job");
res
.status(400)
.json(err);
}else{
console.log("Job Created", job);
res
.status(201)
.json(job);
}
});
}
jobs.model.js
var mongoose = require('mongoose');
var jobSchema = new mongoose.Schema({
_id: {
type: String
},
desc: {
type: String
},
type: {
type: String,
default: "TM"
},
location: String
});
mongoose.model('Job', jobSchema);
db.js
var mongoose = require ('mongoose');
var dburl = 'mongodb://localhost:27017/dbname';
mongoose.connect(dburl);
mongoose.connection.on('connected', function(){
console.log('Mongoose connected to ' + dburl);
});
mongoose.connection.on('disconnected', function(){
console.log('Mongoose disconnedted');
});
mongoose.connection.on('error', function(err){
console.log('Mongoose connection error: ' + err);
});
require('./jobs.model.js');
index.js
var express = require('express');
var router = express.Router();
var ctrlJobs = require('../controllers/jobs.controllers.js');
router
.route('/jobs')
.get(ctrlJobs.jobsGetAll)
.post(ctrlJobs.addNewJob);
module.exports = router;
app.js
require('./api/data/db.js');
var express = require('express');
var app = express ();
var path = require('path');
var bodyParser = require('body-parser');
var routes = require('./api/routes');
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next();
});
app.use(express.static(path.join(__dirname, 'public')));
app.use(bodyParser.urlencoded({extended: false}));
app.use('/api', routes);//Goes to index.js
jobs.service
import { Injectable } from '@angular/core';
import { Http, Response, Headers, RequestOptions } from '@angular/http';
import { Observable } from 'rxjs/Rx';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';
@Injectable()
export class JobsService{
private _url = "http://123.456.789.100/api/jobs"; //removed actual address for post
constructor(private _http: Http){}
addNewJob(form: Object){
let headers = new Headers({'Content-Type':'application/json'});
let options = new RequestOptions({headers: headers});
return this._http
.post(this._url, JSON.stringify(form), options)
.map(this.extractData)
.catch(this.handleError);
}
private extractData(res: Response){
let body = res.json();
return body.data || { };
}
private handleError (error: Response | any) {
let errMsg: string;
if (error instanceof Response) {
const body = error.json() || '';
const err = body.error || JSON.stringify(body);
errMsg = `${error.status} - ${error.statusText || ''} ${err}`;
} else {
errMsg = error.message ? error.message : error.toString();
}
console.error(errMsg);
return Observable.throw(errMsg);
}
}
job-form.component
import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { Router, ActivatedRoute } from '@angular/router';
import { JobsService } from './jobs.service';
@Component({
templateUrl: './job-form.component.html',
providers: [JobsService]
})
export class JobFormComponent implements OnInit {
id: string;
job: any;
jobForm: FormGroup;
title: string;
constructor(
private _fb: FormBuilder,
private _router: Router,
private _route: ActivatedRoute,
private _jobsService: JobsService
){
}
ngOnInit(): void {
this.jobForm = this._fb.group({
jobid: ['', Validators.required],
name: ['', Validators.required],
jobType: ['', Validators.required],
location: ['', Validators.required]
});
this.id = this._route.snapshot.params['id'];
this.title = this.id ? "Edit Job" : "Create New Job";
}
save(form: any){
console.log(this.jobForm.value);
this._jobsService.addNewJob(form).subscribe((dataResponse) => {
console.log("Submitting" + dataResponse);
});
}
reset(){
this.jobForm.reset();
}
}
job-form.component.html
<form [formGroup]="jobForm" novalidate (ngSubmit)="save(jobForm.value)">
<div class="row">
<div class="col-xs-2">
<label>Job Number</label>
<input [ngModel]="job?.jobid ? job.jobid : ''" class="form-control" type="text" formControlName="jobid">
</div>
<div class="col-xs-8">
<label>Title</label>
<input [ngModel]="job?.name ? job.name : ''" class="form-control" type="text" formControlName="name">
</div>
<div class="col-xs-2">
<label>Type</label><br />
<select [ngModel]="job?.jobType ? job.jobType : ''"class="form-control" formControlName="jobType">
<option value="TM">T&M</option>
<option value="LS">Lump Sum</option>
</select>
</div>
</div>
<div class="row">
<div class="col-xs-2">
<label>Status</label><br />
<select class="form-control" formControlName="status" [ngModel]="job?.status ? job.status : ''">
<option value="Pending">Pending</option>
<option value="Active">Active</option>
<option value="On Hold">On Hold</option>
<option value="Complete">Complete</option>
<option value="Closed">Closed</option>
</select>
</div>
<div class="col-xs-5">
<label>Location</label>
<input [ngModel]="job?.location ? job.location : ''" class="form-control" type="text" formControlName="location">
</div>
</div>
<br />
<div class="row">
<div class="col-xs-1">
<button type="btn btn-primary" class="btn btn-primary" [disabled]="!jobForm.valid">Submit</button>
</div>
<div class="col-xs-1">
<button class="btn btn-default" (click)="reset()">Reset</button>
</div>
</div>
</form>
With the headers set to application/json the req.body is an empty object
{}
When I set the headers to application/x-www-form-urlencoded the req.body shows
{ '{"jobid":"8746541","name":"asdfasdfasdfasdf","jobType":"LS","location":"asdfa"}':''}
on submit XHR
PostmanSuccess
Upvotes: 0
Views: 2326
Reputation: 31
1.At front end level:- When using reactive driven forms Pass the front end class file binding object as getRawValue().
1.1 At front end to backend integration
such as service in which our definite
method when call we have to pass the
binded object with when saving includes
headers as though it was post method.
Add middleware by requiring bodyparser. Use use as a bodyparser.json.
Navigate to particular route in postman and first check with new data and post it.
Now bind with front end object.
What we are passing to post rest API method was object from front end side.
Happy ending 😃
Upvotes: 0
Reputation: 1856
in a file jobs.service you are setting Header to
'Content-Type':'application/json'
in a file index.js you are handling body request
app.use(bodyParser.urlencoded({extended: false}));
so there are two solution you can do.
1.) Either change in a jobs.service
'Content-Type': 'application/x-www-form-urlencoded'
2.) Or change in index.js
app.use(bodyParser.json());
Upvotes: 2
Reputation: 895
In app.js add the following middlewares...
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));
For more information visit this site:link!
Upvotes: 0
Reputation: 27
Solution
Added line app.use(bodyParser.json());
to app.js. Essentially, this tells the application that it should natively understand JSON. Submitting the form in the application now results in a new record being added to mongodb.
Upvotes: 1