Angularjs with rails API rest post 400 (bad request) - javascript

Hello i making a project of rails api and angularJs,And I found the following error.
angular.js:11821 POST http://localhost:3000/people 400 (Bad Request)
And I could not find why.
code below.
Rails Controller
# POST /people
def create
#person = Person.new(person_params)
if #person.save
render json: #person, status: :created, location: #person
else
render json: #person.errors, status: :unprocessable_entity
end
end
AngularJS
$scope.SendData = function () {
// use $.param jQuery function to serialize data from JSON
var data = $.param({
name: $scope.name,
age: $scope.age,
gender:$scope.gender,
lonlat:$scope.lonlat
});
var config = {
headers : {
'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8;'
}
}
$http.post('http://localhost:3000/people', data, config)
.then(function (data, status, headers, config) {
$scope.PostDataResponse = data;
})
.catch(function (data, status, header, config) {
$scope.ResponseDetails = "Data: " + data +
"<hr />status: " + status +
"<hr />headers: " + header +
"<hr />config: " + config;
});
};
Html
<div ng-app="myApp" ng-controller="person">
<div class="modal-body">
<div class="form-group">
<label for="exampleInputEmail1">Name:</label>
<input type="text" class="form-control" name="name" ng-model="name" placeholder="Email">
</div>
<div class="form-group">
<label for="exampleInputEmail1">age:</label>
<input type="text" class="form-control" name="age" ng-model="age" placeholder="Email">
</div>
<div class="form-group">
<label for="exampleInputEmail1">gender:</label>
<input type="text" class="form-control" name="gender" ng-model="gender" placeholder="Email">
</div>
<div class="form-group">
<label for="exampleInputEmail1">lonlat:</label>
<input type="text" class="form-control" name="lonlat" ng-model="lonlat" placeholder="Email">
</div>
<button ng-click="SendData()"
class="btn btn-default">Submit</button>
{{ PostDataResponse }}
thanks for listening

I cannot see your person_params definition, but if it is like when produced by rails generators, you are missing to wrap your params in a person hash
var data = $.param({person:
{ name: $scope.name,
age: $scope.age,
gender:$scope.gender,
lonlat:$scope.lonlat }
});

Related

Clean way of posting form data with Angular?

I was wondering, what's the clean way of posting form data with angular?
I have this form setup
<div id="contact-form" class="row">
<div class="col-sm-4 col-sm-offset-4 text-center">
<form>
<div class="form-group">
<input type="text" class="form-control input-lg text-center" placeholder="Firstname" name="firstname" ng-model="firstname">
</div>
<div class="form-group">
<input type="text" class="form-control input-lg text-center" placeholder="Lastname" name="lastname" ng-model="lastname">
</div>
<div class="form-group">
<input type="email" class="form-control input-lg text-center" placeholder="Email" name="email"ng-model="email">
</div>
<!-- Submit Contact -->
<button type="submit" class="btn btn-primary btn-lg" ng-click="createContact()">Add</button>
</form>
</div>
</div>
and I'm posting this to a node.js backend "api".
How do I do this correctly? Do I write every api request in 1 core file? Do I make separate files for each page?
And then how I do I write a clean request?
$scope.createContact = function() {
$http.post('/contacts', ...)
.success(function(data) {
})
.error(function(data) {
});
};
I want to process 'lastname', 'firstname' and 'email' to add a new contact, but online I can't find a good, clean way to write this.
Here's my model in case it helps:
var mongoose = require('mongoose');
var ContactSchema = new mongoose.Schema({
firstname: { type: String, require: true },
lastname: { type: String, require: true },
email: { type: String, require: true }
});
module.exports = mongoose.model('Contact', ContactSchema);
Here's the code I used in the end.
$scope.createContact = function(contact) {
$scope.contact = { firstname: $scope.firstname, lastname: $scope.lastname, email: $scope.email };
$http.post('/contacts', $scope.contact)
.success(function(data) {
$scope.contact = {firstname:'',lastname: '', email:''}; // clear the form so our user is ready to enter another
$scope.contacts = data;
console.log(data);
})
.error(function(data) {
console.log('Error: ' + data);
});
};
How you structure your project is up to you. You could do it all in one file (but that's not very scalable), You could do one in each file (I wouldn't recommend it), or you could group them into semantic files like user_routes.js, social_media_routes.js, etc.
You are on the right track using $http.post() You'll want to create a JSON using your bound variables. You haven't included your entire controller so it's hard to tell you what to do. But a better way of doing this would probably just to create a JSON with empty values like this:
$scope.contact = {
firstname: '',
lastname: '',
email: '',
}
and then use something like ng-model="contact.firstname" for your data-binding. This will let you simply send $scope.contact to the back-end route.
The back-end route in Express would look something like:
var express = require('express');
var app = express();
app.post('/contacts', function (req, res) {
res.status(200).send(req)
}
This will send back what it receives - That should be enough to get you started - Handling POST requests in Express will depend on what version of Express you are using.
In the form tag add the attribute ng-submit to trigger directly in angular the post function.
<div id="contact-form" class="row">
<div class="col-sm-4 col-sm-offset-4 text-center">
<form ng-submit="createContact(user)">
<div class="form-group">
<input type="text" class="form-control input-lg text-center" placeholder="Firstname" name="firstname" ng-model="user.firstname">
</div>
<div class="form-group">
<input type="text" class="form-control input-lg text-center" placeholder="Lastname" name="lastname" ng-model="user.lastname">
</div>
<div class="form-group">
<input type="email" class="form-control input-lg text-center" placeholder="Email" name="email"ng-model="user.email">
</div>
<!-- Submit Contact -->
<button type="submit" class="btn btn-primary btn-lg">Add</button>
</form>
</div>
Add an empty user object in the controller:
$scope.user = {firstname:'',lastname: '', email:''};
Let the $http service handle the call:
$scope.createContact = function(user) {
$http.post('/contacts', user)
.then(function(data) {
//in data.data is the result of the call
},function(error) {
//here is the error if your call dont succeed
});};

Server response message

I need to get server response error message to show in form after submit. I get message if i use this code in js
.error(function (data, status, header, config) {
$scope.postDataSuccessfully = false;
var messages = [];
angular.forEach(data.errors, function (value, key) {
$scope.ResponseDetails = "Data: " + data +
"<hr />status: " + status +
"<hr />headers: " + header +
"<hr />config: " + config;
messages.push('Error! ' + key + ' is not correct');
});
$scope.messages = messages;
});
and in html
<div ng-repeat="message in messages track by $index">
<div data-ng-hide="message == ''" data-ng-class="(postDataSuccessfully) ? 'alert alert-success' : 'alert alert-danger'">
{{message}}
</div>
</div>
but this is only shown on one place after submit, like on this image
I want to have message on field with error, like on next image
Here is my html code for this form input
<div class="form-group">
<label for="type" class="col-sm-3 control-label">{{'TYPE'| translate}}</label>
<div class="col-sm-9">
<select class="form-control" id="type" name="type" ng-model="type">
<option ng-repeat="type in types" value="{{type}}">{{type}}</option>
</select>
</div>
</div>
<div class="form-group">
<label for="description" class="col-sm-3 control-label">{{'DESCRIPTION'| translate}}</label>
<div class="col-sm-9">
<textarea type="text" rows="3" class="form-control" id="description" name="description" ng-model="description" placeholder="description"></textarea>
<br>
</div>
</div>
you have two options :
either you put for each field an error message and display it when it occur
<div ng-messages="myForm.myselect.$error" ng-if="myForm.$submitted || myForm.myselect.$touched">
<div ng-message="required">myselect is required.</div>
</div>
or alternatively you can use the toast popup error msgs :
$scope.validateMyData = function() {
var errorType = callYourServerService();
if(errorType === "myFirstField") {
toaster.pop('error', "Error", "Please insert valid value for myFirstField");
}
if(errorType === "mySecondField") {
toaster.pop('error', "Error", "Please insert valid value for mySecondField");
}
... etc

How to change the url

I want to change the URL of the update operation. The end point of the URL should be gotten from an input. How can I achieve this? The following doesn't work.
$(document).ready(function(){
$.fn.serializeObject = function()
{
var o = {};
var a = this.serializeArray();
$.each(a, function() {
if (o[this.name] !== undefined) {
if (!o[this.name].push) {
o[this.name] = [o[this.name]];
}
o[this.name].push(this.value || '');
} else {
o[this.name] = this.value || '';
}
});
return {"issue":o};
};
<form role="form">
<div class="form-group input-group">
<div class="row">
<div class="col-md-6">
<label>Issue ID * </label>
<select class="form-control selectclass" id="issueid"></select>
</div>
<div class="col-md-6">
<label>Tracker * </label>
<select class="form-control" name="tracker" id="tracker">
<option value="1">Bug</option>
<option value="2">Feature</option>
<option value="3">Support</option>
</select>
</div>
</div>
</div>
<div class="form-group">
<label>Subject </label>
<input class="form-control" placeholder="Issue Subject" name="subject" id="subject">
</div>
<div class="form-group">
<label>Description</label>
<textarea class="form-control" rows="6" name="description" id="description"></textarea>
</div>
<button type="submit" id="submit" class="btn btn-default">Submit Button</button>
<button type="reset" class="btn btn-default">Reset Button</button>
</form>
$('#submit').on('click', function(){
var x=document.getElementById('issueid').value;
$.ajax({
type : 'PUT',
url: 'http://localhost/redmine/issues'+ x +'.json',
contentType:'application/json',
data:JSON.stringify($('form').serializeObject()), // post data || get data
success : function(msg, status, jqXHR) {
console.log(msg, status, jqXHR);
},
error: function(xhr, resp, text) {
console.log(xhr, resp, text);
}
})
console.log(x);
});
});
Inputs are gotten from a form and sent to Redmine API. URL should look like below, http://localhost/redmine/issues/2.json
When dynamically populating your id="issueid" select make sure that you properly set the value attribute of the options:
$('.selectclass').append('<option value="' + value.id + '">' + value.id + '<option>');
Also fix the url for your next AJAX request by adding a trailing / after issues:
url: 'http://localhost/redmine/issues/' + x + '.json'

AngularJS $scope data is not showing any thing

The submitform() does not take the for datas to the function. Chrome console says ReferenceError: $ is not defined. Is there anything wrong in the code ?
var app = angular.module('app', []);
app.controller('testimonialController', function($scope, $http) {
$scope.formdata = {};
$scope.submission = false;
$scope.submitform = function($scope, $http) {
$http({
method: 'POST',
url: 'sendmail.php',
data: $.param($scope.formdata), // pass in data as strings
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
} // set the headers so angular passing info as form data (not request payload)
}).
success(function() {
console.log("send successfuly");
}).
error(function() {
console.log("It is failed");
});
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div id="contact-form" ng-controller="testimonialController" ng-app="app">
<h1 id="contact">Contact</h1>
<pre>Form data: {{formdata}}</pre>
<p>Take a look around the site, Do you have something in mind you would like to let me know .You can contact me by filling the form below or email hello#athimannil.com</p>
<form ng-submit="submitform()">
<div class="form-wrap">
<label for="name">Name</label>
<input type="text" name="name" ng-model="formdata.name" placeholder="Name" required>
<br>
</div>
<div class="form-wrap">
<label for="email">Email</label>
<input type="email" name="email" ng-model="formdata.email" placeholder="Email" required>
<br>
</div>
<div class="form-wrap">
<label for="comment">Message</label>
<br>
<textarea name="comment" id="comment" ng-model="formdata.comment" placeholder="Comment" cols="30" rows="10" required></textarea>
<br>
</div>
<input type="submit" name="submit" value="Send">
</form>
</div>
This is the console message when use
$http({
method : 'POST',
url : 'sendmail.php',
data : $scope.formdata, // pass in data as strings
headers : { 'Content-Type': 'application/x-www-form-urlencoded' } // set the headers so angular passing info as form data (not request payload)
}).
data: $.param($scope.formdata)
This line uses jQuery's $.param method. You have to include it, if you want to use it

submit form data to serverside

<form ng-submit="doRegister()">
<div class="control-group">
<label for="email">E-Mail Address</label>
<input type="email" id="email" name="email" ng-model="user.email" autofocus>
</div>
<div class="control-group">
<label for="password">Password</label>
<input type="password" id="password" name="user.password" ng-model="password">
</div>
<div class="control-group">
<label for="password_confirmation">Confirm Password</label>
<input type="password" id="password_confirmation" name="password_confirmation" ng-model="user.password_confirmation">
</div>
<input type="submit">
</form>
How do I submit the form to register via POST? Technically I don't know where data could be placed.
function registerCtrl ($scope, $http) {
document.title = 'Register';
$scope.doRegister = function(){
$http.post('/register', data).
success(function(data, status, headers, config) {
console.log(data);
}).
error(function(data, status, headers, config) {
angular.element('.errors').html(data.errors.join('<br>')).slideDown();
});
};
}
EDIT: Progress:
function registerCtrl ($scope, $http) {
document.title = 'Register';
$scope.user = {};
$scope.doRegister = function(){
$http.post('/register', $scope.user);
};
}
but the request sent to the server was an empty array in php:
Array()
You already have a properties binded within the form.
You can define data using them.
For example, for email field:
var data = {};
data.email = $scope.email;
Or you can even define $scope.data = {} in controller,
and post it.
EDIT on 9/14
This seems to be one of the problem that people see with $http.post() for sending
form data. Solution is given in the following Q&A.
AngularJS - Any way for $http.post to send request parameters instead of JSON?
You need to declare variables and change headers like this:
function registerCtrl ($scope, $http) {
document.title = 'Register';
$scope.user = {
email: '',
password: ''
};
$scope.doRegister = function(){
$http({
url: '/register',
data: $scope.user,
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
transformRequest: function(obj) {
var str = [];
for(var p in obj)
str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
return str.join("&");
},
});
};
}
And you need
AngularJS' post method sends data as Request Payload.
Just use:
$json = json_decode(file_get_contents("php://input"));
You can access values in php by using
$email = $json->email;
$password = $json->password;
$password_confirmation = $json->password_confirmation;
<form id="Register" action="/register">
<div class="control-group">
<label for="email">E-Mail Address</label>
<input type="email" id="email" name="email" ng-model="email" autofocus>
</div>
<div class="control-group">
<label for="password">Password</label>
<input type="password" id="password" name="password" ng-model="password">
</div>
<div class="control-group">
<label for="password_confirmation">Confirm Password</label>
<input type="password" id="password_confirmation" name="password_confirmation" ng-model="password_confirmation">
</div>
<input type="submit">
</form>
call ajax function.
$.ajax({
url: form.prop('action'),
type: 'POST',
data: form.serialize(),
dataType: 'json',
async: false,
success: function (result) {
}
}); // ajax post end
var form = $("#Register");
data pass form.serialize() that is very easy to pass data from server side.

Categories