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!
Related
Hello wenn i want to send a post request to my Controller there is no data.
I tried to log my Json file and there is something. But when I send the post request my controller shows it is empty.
Here is my call:
var item = {};
var jsonObj = [];
item["ProductCategoryId"] = i;
item["Name"] = txtName;
item["Description"] = txtDescription;
item["Price"] = txtPrice;
item["Stock"] = txtStock;
item["ProductCategory"] = txtProductCategory;
item["Image"] = await getAsByteArray(txtImage);
jsonObj.push(item);
var jsonString = JSON.stringify(jsonObj);
console.log("jsonString : " + jsonString);
$.ajax({
url: "/Admin/SaveProductToDB",
type: "POST",
data: { dataToSend: jsonString},
success: function (data) {
if (data.status == "Success") {
BootstrapDialog.show({
title: 'Success!',
message: "Data Updated Successfully!",
buttons: [{
label: 'OK',
action: function (dialog) {
window.location.href = "/Admin/Product";
removeProdData(i);
$("#btnAddProd").attr("disabled",false);
dialog.close();
}
}]
});
}
}
});
//Here I make a breakpoint but my string is empty
public JsonResult SaveProductToDB(string dataToSend)
{
List<Product> _List = Newtonsoft.Json.JsonConvert.DeserializeObject<List<Product>>(dataToSend);
}
the getAsByteArray
async function getAsByteArray(file) {
return new Uint8Array(await readFile(file))
}
function readFile(file) {
return new Promise((resolve, reject) => {
// Create file reader
let reader = new FileReader()
// Register event listeners
reader.addEventListener("loadend", e => resolve(e.target.result))
reader.addEventListener("error", reject)
// Read file
reader.readAsArrayBuffer(file)
})
}
I found out if I remove the Image. that the controller is then able to resize it. Thanks for the help so far. So I need to look at this place where the problem is.
You are checking against data.status as if it's a given that it exists. Just console.log(data) instead and you will see whether or not status is being returned.
Also, if you open the Network tab in Chrome you can click on the post request & see if your headers are going through accurately and also click on 'Preview' to see an unfiltered result from the controller.
You might want to modify your code to catch errors for debugging, ie:
$.ajax({
url: "/Admin/SaveProductToDB",
type: "POST",
data: { dataToSend: jsonString},
success: function (data) {
if (data.status == "Success") {
BootstrapDialog.show({
title: 'Success!',
message: "Data Updated Successfully!",
buttons: [{
label: 'OK',
action: function (dialog) {
window.location.href = "/Admin/Product";
removeProdData(i);
$("#btnAddProd").attr("disabled",false);
dialog.close();
}
}]
});
}
},
error:function (xhr, ajaxOptions, thrownError) {
// Set up whatever error reaction you want, here. ie:
console.log('An error was encountered.');
alert(xhr.status);
alert(thrownError);
}
});
Another tip is to validate empty data being submitted prior to the Ajax call, so you only touch the backend server when your data is valid - to avoid an error.
Hi i tried following this tutorial to use authentication with google plus https://stackoverflow.com/questions/23930744/how-to-use-google-login-api-with-cordova-phonegap but the prolem is when i click to login button it open browser and load google plus from browser. What i want is when i click the login button its pop up the google plus app like other native app ? The question is can i achive that with cordova ? and if yes how do i do that ? thanks
here is how to login with google based on that stacoverflow answer above
var googleapi = {
authorize: function(options) {
var deferred = $.Deferred();
//Build the OAuth consent page URL
var authUrl = 'https://accounts.google.com/o/oauth2/auth?' + $.param({
client_id: options.client_id,
redirect_uri: options.redirect_uri,
response_type: 'code',
scope: options.scope
});
//Open the OAuth consent page in the InAppBrowser
var authWindow = window.open(authUrl, '_blank', 'location=no,toolbar=no');
//The recommendation is to use the redirect_uri "urn:ietf:wg:oauth:2.0:oob"
//which sets the authorization code in the browser's title. However, we can't
//access the title of the InAppBrowser.
//
//Instead, we pass a bogus redirect_uri of "http://localhost", which means the
//authorization code will get set in the url. We can access the url in the
//loadstart and loadstop events. So if we bind the loadstart event, we can
//find the authorization code and close the InAppBrowser after the user
//has granted us access to their data.
$(authWindow).on('loadstart', function(e) {
var url = e.originalEvent.url;
var code = /\?code=(.+)$/.exec(url);
var error = /\?error=(.+)$/.exec(url);
if (code || error) {
//Always close the browser when match is found
authWindow.close();
}
if (code) {
//Exchange the authorization code for an access token
$.post('https://accounts.google.com/o/oauth2/token', {
code: code[1],
client_id: options.client_id,
client_secret: options.client_secret,
redirect_uri: options.redirect_uri,
grant_type: 'authorization_code'
}).done(function(data) {
deferred.resolve(data);
$("#loginStatus").html('Name: ' + data.given_name);
}).fail(function(response) {
deferred.reject(response.responseJSON);
});
} else if (error) {
//The user denied access to the app
deferred.reject({
error: error[1]
});
}
});
return deferred.promise();
}
};
var accessToken;
var UserData = null;
function callGoogle() {
// alert('starting');
googleapi.authorize({
client_id: 'client_id',
client_secret: 'Client_Secret',
redirect_uri: 'http://localhost',
scope: 'https://www.googleapis.com/auth/plus.login https://www.googleapis.com/auth/userinfo.email'
}).done(function(data) {
accessToken = data.access_token;
// alert(accessToken);
// $loginStatus.html('Access Token: ' + data.access_token);
console.log(data.access_token);
console.log(JSON.stringify(data));
getDataProfile();
});
}
// This function gets data of user.
function getDataProfile() {
var term = null;
// alert("getting user data="+accessToken);
$.ajax({
url: 'https://www.googleapis.com/oauth2/v1/userinfo?alt=json&access_token=' + accessToken,
type: 'GET',
data: term,
dataType: 'json',
error: function(jqXHR, text_status, strError) {},
success: function(data) {
var item;
console.log(JSON.stringify(data));
// Save the userprofile data in your localStorage.
localStorage.gmailLogin = "true";
localStorage.gmailID = data.id;
localStorage.gmailEmail = data.email;
localStorage.gmailFirstName = data.given_name;
localStorage.gmailLastName = data.family_name;
localStorage.gmailProfilePicture = data.picture;
localStorage.gmailGender = data.gender;
}
});
disconnectUser();
}
function disconnectUser() {
var revokeUrl = 'https://accounts.google.com/o/oauth2/revoke?token=' + accessToken;
// Perform an asynchronous GET request.
$.ajax({
type: 'GET',
url: revokeUrl,
async: false,
contentType: "application/json",
dataType: 'jsonp',
success: function(nullResponse) {
// Do something now that user is disconnected
// The response is always undefined.
accessToken = null;
console.log(JSON.stringify(nullResponse));
console.log("-----signed out..!!----" + accessToken);
},
error: function(e) {
// Handle the error
// console.log(e);
// You could point users to manually disconnect if unsuccessful
// https://plus.google.com/apps
}
});
}
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)
});
I have used $.ajax to send a PUT request through to my Express server. I can retrieve the information just fine but am having difficulties saving the new changes to my mongo (via mongoskin) database.
From the top, here is my click event on an edit button:
$('#userList table tbody').on('click', 'td a.linkedituser', editUser);
And here the function it calls:
function editUser(event) {
event.preventDefault();
var thisUserID = $(this).attr('rel');
var arrayPosition = userListData.map(function(arrayItem) { return arrayItem._id; }).indexOf(thisUserID);
var thisUserObject = userListData[arrayPosition];
$('#editUserName').val(thisUserObject.email);
$('#editUserEmail').val(thisUserObject.email);
$('#editUserFullname').val(thisUserObject.fullname);
$('#editUserAge').val(thisUserObject.age);
$('#editUserLocation').val(thisUserObject.location);
$('#editUserGender').val(thisUserObject.gender);
$('#btnEditUser').on('click', function() {
$.ajax({
type: 'PUT',
url: '/users/edituser',
data: {
'id' : thisUserID,
'username' : $('#editUserName').val(),
'email' : $('#editUserEmail').val(),
'fullname' : $('#editUserFullname').val(),
'age' : $('#editUserAge').val(),
'location' : $('#editUserLocation').val(),
'gender' : $('#editUserGender').val()
},
dataType: 'json',
success: function(msg) {},
error: function(err) {}
}).done(function(response) {
if (response.msg === '') {
}
else {
}
populateTable();
});
});
};
And finally the router file routes/users.js
router.put('/edituser', function(req, res) {
var db = req.db;
db.collection('userlist').findById(req.body.id, function(err, result) {
result.username = req.body.username;
result.email = req.body.email;
result.fullname = req.body.fullname;
result.age = req.body.age;
result.location = req.body.location;
result.gender = req.body.gender;
console.log(result);
res.send((result === 1) ? { msg: '' } : { msg: 'error: ' + err + "!!!!" });
});
});
Everything is on git should I have missed anything.
It seems like everything should be fine but the results are not saving. When I refresh the page or click the edit button the old values return. I tried 'results.save()' but I get an error that the function does not exist.
Should I not be using findById?
Thanks.
I am trying to use Facebook Graph API to get information about users who logged in via Facebook.
At the beginning, I was using only one function and no errors occurred; But then, I added another function that uses Facebook API. From that moment, none of the functions works. Only when I remove the new function, the old one works again...
I guess the code will be much understandable than what I described above:
function fb_login(){
FB.login(function(response) {
if (response.authResponse) {
access_token = response.authResponse.accessToken; //get access token
user_id = response.authResponse.userID; //get FB UID
FB.api('/me', function(response) {
user_email = response.email; //get user email
$.ajax({
type: "POST",
url: "http://*******/ajax.php",
data: { action: "login", id: user_id, email: user_email, first_name: response.first_name, last_name: response.last_name }
}).done(function( msg ) {
alert( "Data Saved: " + msg );
});
});
} else {
//user hit cancel button
console.log('User cancelled login or did not fully authorize.');
}
}, {
scope: 'publish_actions,email,read_stream,publish_stream'
});
}
The function above will work unless the function below exists.
function update_autopost(form)
{
FB.api('/me', function(response) {
var autopost_value = form.autopost.checked;
if(autopost_value == false)
{
autopost_value = "off";
}
else{
autopost_value = "on";
}
$.ajax({
type: "POST",
url: "http://*********/ajax.php",
data: { action: "update", id: response.authResponse.userID, autopost: autopost_value }
}).done(function( msg ) {
alert( "Data Saved: " + msg );
});
});
}
To be more detailed, after adding the second function, two things happens:
The first function stops working.
The second function is not able to get information from Facebook Graph API (for instance, response.authResponse.userID doesn't work).