I've been developing a simple RESTful API with NodeJS and Express. When the backend was done and operative, my next step was to make HTML forms to fill the database and consume the API. I decided that using jQuery to submit the data would be a nice idea to get some practice .
So basically I want to get from a $.post the body and status that my app's backend generates whenever it recieves a POST request. Here's the form's script:
$('#addcube').submit(function(event){
//Stop the default behaviour of the submit button
event.preventDefault();
//Get the input values
var $form = $(this),
postData = {
nombre: $form.find('input[name="nombre"]').val(),
brand: $form.find('input[name="brand"]').val(),
capas: $form.find('input[name="capas"]').val(),
kind: $form.find('input[name="kind"]').val()
},
url = $form.attr('action');
$.ajax({
url: url,
type: 'post',
data: JSON.stringify(postData),
contentType: "application/json",
done: function(cube, textStatus, jqxhr){
console.log(JSON.parse(cube));
},
fail: function(jqxhr, textStatus, errorThrown){
console.log(errorThrown.msg);
}
});
});
And here's the backend route for that post:
app.post('/api/cube', cubeController.addCubo);
Which is controlled by this script:
module.exports.addCubo = function(req, res){
var Cube = require('../models/cube');
console.log('POST');
try{
console.log(req.body);
var cubo = new Cube({
nombre : req.body.nombre,
brand : req.body.brand,
capas : req.body.capas,
kind : req.body.kind
});
cubo.save(function(err){
if(!err){
console.log('Nuevo cubo guardado.');
res.send(JSON.stringify(cubo));
res.status(200);
}else{
console.log('Error al guardar: '+err);
res.send('{"status":"400","msg":"bad_request"}');
res.status(400);
}
});
}catch(err){
res.send('{"status":"500","msg":"internal_server_error"}');
}
};
No body property exists at response, use . Set $.post() type to json, or use JSON.parse() at .done(). Also, if sending error, use .fail() to log messages
var send = $.post(url, {
nombre : name,
brand : marca,
capas : layers,
kind : tipo
}, "json"); // set expected response type to `"json"`
// Try to get the result
send.done(function(cube, textStatus) {
console.log(cube, textStatus)
});
// handle errors
send.fail(function(jqxhr, textStatus, errorThrown) {
console.log(textStatus, errorThrown, errorThrown.msg)
});
Related
I need to send an XML type data to backend using jquery, ajax as a DELETE request. This returns empty array from backend request body. How can I send id properly?
here is my code,
function deleteProduct(id) {
var xmlDocument = $(
`<productsData>
<Prod_ID>${id}</Prod_ID>
</productsData>`);
$.ajax({
type:"DELETE",
url:"http://localhost:8000/delete",
data:JSON.stringify({
data : xmlDocument
}),
contentType: 'application/json',
dataType: 'text'
});
}
I need to send this data,
<productsData>
<Prod_ID>2</Prod_ID>
</productsData>
this 2 comes from the function parameter.
this is my backend in express
app.delete('/delete',(req,res,next)=>{
console.log(req.body);
res.status(200).json({
message: "success"
})
})
this returns empty object.How can I solve this?
If you want to send XML, don't say you're sending application/json:
function deleteProduct(id) {
return $.ajax({
type: "DELETE",
url: "http://localhost:8000/delete",
data: `<productsData><Prod_ID>${id}</Prod_ID></productsData>`,
contentType: 'application/xml'
});
}
By returning the Ajax request, you can do something like this:
deleteProduct(42).done(function () {
// delete completed, remove e.g. table row...
}).fail(function (jqXhr, status, error) {
// delete failed, keep table row & show alert
alert("Could not delete product: " + error);
});
Hello I am not good with ajax.I want to check my login info and return either 'success' or 'fail'.Buy my ajax seems to have an error.
var user = $('.username').value();
var pass = $('.password').value();
$.ajax({
type : 'POST',
url : 'login_check.php',
data : {
'username': user,
'password': pass
},
beforeSend: function() {
$("#Loading").show();
},
success : function(response) {
if(response=="success" && response!=="fail") {
$('.status').html("Success! Now logging in ......");
setTimeout(' window.location.href = "index.php"; ',4000);
} else {
$('#Loading i').hide();
$('.status').html("Login fail! Please use correct credentials....");
setTimeout(' window.location.href = "login.php"; ',4000);
}
}
});
Can anyone points me out?
The reason you are getting error is because your javascript is getting break(giving error) at $('.username').value(); as there is no value() function. If you open console you get this error. So because of this rest of script is not working. So change $('.username').value(); to this $('.username').val(); and same for the var pass = $('.password').value(); change to var pass = $('.password').val(); and also you don't need if condition as mention in comment. Your final code will be something like this.
var user = $('.username').val();
var pass = $('.password').val();
$.ajax({
type: 'POST',
url: //some url
data: {
'username': user,
'password': pass,
},
beforeSend: function() {
//some code
},
success: function(response) {
// some code which you want to excute on success of api
},
error: function(xhr, status, error) {
// some code which you want to excute on failure of api
}
});
I dont have the whole code for your app but when it come to your ajax request your code should look like this , for a more accurate answer please show the error that you are getting
var user = $('.username').val();
var pass = $('.password').val();
$.ajax({
type : 'POST',
url : 'login_check.php',
data : {
'username':user,
'password':pass,
},
beforeSend: function()
{
$("#Loading").show();
},
success : function(response)
{
$('.status').html("Success! Now logging in ......");
setTimeout(()=>{ window.location.href = "index.php"; },4000);
},
error: function(xhr, status, error) {
$('#Loading i').hide();
$('.status').html("Login fail! Please use correct credentials....");
setTimeout(()=>{ window.location.href = "login.php"},4000);
}
});
Your response needs to be a PHP echo that returns a string with a value of either ”success” or ”fail”.
Your PHP response after successful login:
echo(‘success’);
Your PHP response after failed login:
echo(‘fail’);
A Node.js / Express app with MongoDB, and using Passport, Passport Local and Passport Local Mongoose.
I'm trying allow registered users of my site to update their profiles. My idea was to rehash the signup form and logic, and send the updated data via a PUT request to the server.
The signup uses Ajax to submit the form, and whilst that works OK, when I send a PUT request to update the user, req.body comes back empty and the server throws out an error 500.
The update-form markup and javascript are nearly identical to the signup, so is it because I'm using a PUT request? I'm not even sure if I'm going about this in the right way...
Any pointers would be very happily received!
Edit user form submit logic:
$form.on('submit', function(e) {
if ($form.hasClass('is-uploading')) return false;
$form.addClass('is-uploading').removeClass('is-error');
if (isAdvancedUpload) {
e.preventDefault();
var ajaxData = new FormData($form.get(0));
if (droppedFiles) {
$.each(droppedFiles, function(i, file) {
ajaxData.append($input.attr('name'), file);
});
}
$.ajax({
url: $form.attr('action'),
type: $form.attr('method'),
// data: ajaxData,
dataType: 'json',
cache: false,
contentType: false,
processData: false,
complete: function() {
$form.removeClass('is-uploading');
},
success: function(data) {
// $form.addClass(data.success == true ? 'is-success' : 'is-error');
// if (!data.success) console.log(data);
window.location.replace('/matches');
},
error: function(xhr, textStatus, errorThrown) {
console.log(xhr)
console.log(xhr.statusText);
console.log(textStatus);
console.log(errorThrown); }
});
} else {
var iframeName = 'uploadiframe' + new Date().getTime();
$iframe = $('<iframe name="' + iframeName + '" style="display: none;"></iframe>');
$('body').append($iframe);
$form.attr('target', iframeName);
$iframe.one('load', function() {
var data = JSON.parse($iframe.contents().find('body').text());
$form
.removeClass('is-uploading')
.addClass(data.success == true ? 'is-success' : 'is-error')
.removeAttr('target');
if (!data.success) $errorMsg.text(data.error);
$form.removeAttr('target');
$iframe.remove();
});
};
});
Server Side Edit Route:
// PUT edits
app.put('/users/:_id', function(req, res){
var spokenLangs = req.body.spokenlanguages.split(',');
var learnLangs = req.body.learninglanguages.split(',');
var comms = req.body.commethod.split(',');
var photos = []
req.files.forEach(function(file, i){
photos.push(req.files[i].path.replace('public/', '../'));
});
var updatedUser = new User(
{
username: req.body.username,
firstName: req.body.fname,
lastName: req.body.lname,
age: req.body.age,
gender: req.body.gender,
spokenLanguages: spokenLangs,
learningLanguages: learnLangs,
info: req.body.info,
country: req.body.country,
city: req.body.city,
comMethod: comms,
photos: photos,
lastLogin: Date.now()
}
);
User.findByIdAndUpdate(req.params._id, updatedUser, function(err, user){
if(err){
console.log('error updating user');
console.log(err);
} else {
res.redirect('/matches');
}
});
});
Thank you good people!
I wrote a JQuery script to do a user login POST (tried to do what I have done with C# in the additional information section, see below).
After firing a POST with the JQuery code from my html page, I found the following problems:
1 - I debugged into the server side code, and I know that the POST is received by the server (in ValidateClientAuthentication() function, but not in GrantResourceOwnerCredentials() function).
2 - Also, on the server side, I could not find any sign of the username and password, that should have been posted with postdata. Whereas, with the user-side C# code, when I debugged into the server-side C# code, I could see those values in the context variable. I think, this is the whole source of problems.
3 - The JQuery code calls function getFail().
? - I would like to know, what is this JQuery code doing differently than the C# user side code below, and how do I fix it, so they do the same job?
(My guess: is that JSON.stringify and FormURLEncodedContent do something different)
JQuery/Javascript code:
function logIn() {
var postdata = JSON.stringify(
{
"username": document.getElementById("username").value,
"password": document.getElementById("password").value
});
try {
jQuery.ajax({
type: "POST",
url: "http://localhost:8080/Token",
cache: false,
data: postdata,
dataType: "json",
success: getSuccess,
error: getFail
});
} catch (e) {
alert('Error in logIn');
alert(e);
}
function getSuccess(data, textStatus, jqXHR) {
alert('getSuccess in logIn');
alert(data.Response);
};
function getFail(jqXHR, textStatus, errorThrown) {
alert('getFail in logIn');
alert(jqXHR.status); // prints 0
alert(textStatus); // prints error
alert(errorThrown); // prints empty
};
};
Server-side handling POST (C#):
public override async Task ValidateClientAuthentication(
OAuthValidateClientAuthenticationContext context)
{
// after this line, GrantResourceOwnerCredentials should be called, but it is not.
await Task.FromResult(context.Validated());
}
public override async Task GrantResourceOwnerCredentials(
OAuthGrantResourceOwnerCredentialsContext context)
{
var manager = context.OwinContext.GetUserManager<ApplicationUserManager>();
var user = await manager.FindAsync(context.UserName, context.Password);
if (user == null)
{
context.SetError(
"invalid_grant", "The user name or password is incorrect.");
context.Rejected();
return;
}
// Add claims associated with this user to the ClaimsIdentity object:
var identity = new ClaimsIdentity(context.Options.AuthenticationType);
foreach (var userClaim in user.Claims)
{
identity.AddClaim(new Claim(userClaim.ClaimType, userClaim.ClaimValue));
}
context.Validated(identity);
}
Additional information: In a C# client-side test application for my C# Owin web server, I have the following code to do the POST (works correctly):
User-side POST (C#):
//...
HttpResponseMessage response;
var pairs = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>( "grant_type", "password"),
new KeyValuePair<string, string>( "username", userName ),
new KeyValuePair<string, string> ( "password", password )
};
var content = new FormUrlEncodedContent(pairs);
using (var client = new HttpClient())
{
var tokenEndpoint = new Uri(new Uri(_hostUri), "Token"); //_hostUri = http://localhost:8080/Token
response = await client.PostAsync(tokenEndpoint, content);
}
//...
Unfortunately, dataType controls what jQuery expects the returned data to be, not what data is. To set the content type of the request data (data), you use contentType: "json" instead. (More in the documentation.)
var postdata = JSON.stringify(
{
"username": document.getElementById("username").value,
"password": document.getElementById("password").value
});
jQuery.ajax({
type: "POST",
url: "http://localhost:8080/Token",
cache: false,
data: postdata,
dataType: "json",
contentType: "json", // <=== Added
success: getSuccess,
error: getFail
});
If you weren't trying to send JSON, but instead wanted to send the usual URI-encoded form data, you wouldn't use JSON.stringify at all and would just give the object to jQuery's ajax directly; jQuery will then create the URI-encoded form.
try {
jQuery.ajax({
type: "POST",
url: "http://localhost:8080/Token",
cache: false,
data: {
"username": document.getElementById("username").value,
"password": document.getElementById("password").value
},
dataType: "json",
success: getSuccess,
error: getFail
});
// ...
To add to T.J.'s answer just a bit, another reason that sending JSON to the /token endpoint didn't work is simply that it does not support JSON.
Even if you set $.ajax's contentType option to application/json, like you would to send JSON data to MVC or Web API, /token won't accept that payload. It only supports form URLencoded pairs (e.g. username=dave&password=hunter2). $.ajax does that encoding for you automatically if you pass an object to its data option, like your postdata variable if it hadn't been JSON stringified.
Also, you must remember to include the grant_type=password parameter along with your request (as your PostAsync() code does). The /token endpoint will respond with an "invalid grant type" error otherwise, even if the username and password are actually correct.
You should use jquery's $.param to urlencode the data when sending the form data . AngularJs' $http method currently does not do this.
Like
var loginData = {
grant_type: 'password',
username: $scope.loginForm.email,
password: $scope.loginForm.password
};
$auth.submitLogin($.param(loginData))
.then(function (resp) {
alert("Login Success"); // handle success response
})
.catch(function (resp) {
alert("Login Failed"); // handle error response
});
Since angularjs 1.4 this is pretty trivial with the $httpParamSerializerJQLike:
.controller('myCtrl', function($http, $httpParamSerializerJQLike) {
$http({
method: 'POST',
url: baseUrl,
data: $httpParamSerializerJQLike({
"user":{
"email":"wahxxx#gmail.com",
"password":"123456"
}
}),
headers:
'Content-Type': 'application/x-www-form-urlencoded'
})
})
I have a set of custom user data that I want to make an ajax call to, and in the event that there is no user data, make another ajax call to retrieve a default set of data, and then execute a function after parsing the data. Here's an example:
var oData = [],
exampleUrl = 'example.php';
$.ajax({
url: exampleUrl + '?query=getUserData',
contentType: 'application/json;odata=verbose',
headers: {
'accept': 'application/json;odata=verbose'
},
success : function(data, request){
// Request succeeded
// Check the results
if(data.length){
// There are custom user results!
// Parse the results
oData = data;
}
else{
// There were no custom user results...
// Run another query to retrieve default values
$.ajax({
url: examplUrl + '?query=getDefaultData',
contentType: 'application/json;odata=verbose',
headers: {
'accept': 'application/json;odata=verbose'
},
success : function(data, request){
// Request succeeded
// Check the results
if(data.length){
// There was some default data!
// Parse the results
oData = data;
}
else{
// No data was found...
// Attempt to be helpful
console.log('No Default data was found!');
}
},
error : function(data, request){
// There was an error with the request
// Attempt to be helpful
console.log('Error retrieving data:');
console.log(data);
console.log(request);
}
});
}
},
error : function(data, request){
// There was an error with the request
// Attempt to be helpful
console.log('Error retrieving Custom User data:');
console.log(data);
console.log(request);
},
complete : function(){
// Do something with the data
index.displayData(oData);
}
});
The issue is that if the second ajax call is run, oData doesn't contain any data at all when it's passed to index.displayData(). I'm guessing it has something to do with the asyncronous nature of ajax calls, but shouldn't 'complete' run after everything inside of 'success' runs?
I also know I probably shouldn't be using the ajax "Pyramid of Doom" and should be using promises, but I've tried them and keep getting the same results.
Thank you for your assistance!
As pointed out by Violent Crayon, you could try calling "complete" yourself instead of relying on JQuery's implicit control flow:
function getData(exampleUrl, onComplete){
$.ajax({
success : function(data, request){
if(data.length){
onConplete(data);
}else{
$.ajax({
success : function(data, request){
if(data.length){
onComplete(data);
}else{
console.log('No Default data was found!');
}
},
error : function(data, request){
console.log('Error retrieving data:');
}
});
}
},
error : function(data, request){
console.log('Error retrieving Custom User data:');
}
});
}
var oData = [];
getData('example.php', function(data){
oData = data;
index.displayData(oData);
}
BTW, note how you can have your async functions receive their own return and error callbacks. This can help reduce the pyramid of doom problem without needing to use promises and without needing to hardcode the return callback.
By working with promises, you can avoid the need to pass a callback into your function, and by defining a utility function you can avoid repetition of code.
//reusable utility function, which returns either a resolved or a rejected promise
function fetchData(queryString, cache) {
return $.ajax({
url: 'example.php',
data: { query: queryString },
type: 'JSON',//assumed
cache: cache,
contentType: 'application/json;odata=verbose',
headers: { 'accept': 'application/json;odata=verbose' }
}).then(function(data, textStatus, jqXHR) {
if (data && data.length) {
return data;
} else {
return $.Deferred().reject(jqXHR, 'no data returned').promise();//emulate a jQuery ajax failure
}
});
}
This allows promise methods to be used for a control structure, which :
is concise
uses chaining, not nesting
gives meaningful error messages.
//control structure
fetchData('getUserData', false).then(null, function(jqXHR, textStatus) {
console.log('Error retrieving Custom User data: ' + textStatus);
return fetchData('getDefaultData', true);
}).then(index.displayData, function(jqXHR, textStatus) {
console.log('Error retrieving default data: ' + textStatus);
});
Notes :
the null in .then(null, function(){...}) allows a successful response to drop straight through to the second .then(index.displayData, ...)
default data is cached while the user data is not. This is not necessary to make things work but will be faster next time the default data is required.
in the world of promises, this or something similar is the way to go.