I am trying to do the following from my HTML:
var vm = new Vue({
el: '#loginContent',
data: {
main_message: 'Login',
isLoggedIn: false,
loginError: '',
loginButton:'Login'
},
methods: {
onLogin: function() {
//this.$set(loginSubmit, 'Logging In...');
var data = {
email: $('#email').val(),
password: $('#password').val(),
};
$.ajax({
url: '/api/login',
data: data,
method: 'POST'
}).then(function (response) {
if(response.error) {
console.err("There was an error " + response.error);
this.loginError = 'Error';
} else {
//$('#loginBlock').attr("hidden",true);
console.log(response.user);
if(response.user) {
this.isLoggedIn = true;
} else {
this.loginError = 'User not found';
}
}
}).catch(function (err) {
console.error(err);
});
}
}
});
Basically user presses the login button, onLogin method is called that sends a post to my API. The post is working fine and I do get the response back in the .then() promise.
But, trying to do things like this.isLoggedIn = true; does not update my DOM with what I am expecting the HTML to do when the user logs in.
Could be that I am in some sort of background thread (sorry, mobile developer here) when I get the response in the promise and it can't find the "vm" instance?
Thanks
It is probably happening because your this is not pointing to correct scope, scope of this changes inside an $.ajax call, so you just have to do something like following:
methods: {
onLogin: function() {
//this.$set(loginSubmit, 'Logging In...');
var data = {
email: $('#email').val(),
password: $('#password').val(),
};
var that = this
$.ajax({
url: '/api/login',
data: data,
method: 'POST'
}).then(function (response) {
if(response.error) {
console.err("There was an error " + response.error);
that.loginError = 'Error';
} else {
//$('#loginBlock').attr("hidden",true);
console.log(response.user);
if(response.user) {
that.isLoggedIn = true;
} else {
that.loginError = 'User not found';
}
}
}).catch(function (err) {
console.error(err);
});
}
}
I would propose another method use ES6 Arrow Functions like '=>'. It is simple and do not need extra variable.Like following:
$.ajax({
url: '/api/login',
data: data,
method: 'POST'
}).then((response) => {
if(response.error) {
console.err("There was an error " + response.error);
this.loginError = 'Error';
} else {
//$('#loginBlock').attr("hidden",true);
console.log(response.user);
if(response.user) {
this.isLoggedIn = true;
} else {
this.loginError = 'User not found';
}
}
}).catch(function (err) {
console.error(err);
});
You might want to take a look at axios. I used $.ajax and got it working, but found axios and prefer axios over the ajax library.
Related
I want to show error, or to know why this code run in error:function()
Result is always run to error:function. I want to run success:function(data) and reload this page.
But console don't show anything about error.
https://imgur.com/ZubjYTc
https://imgur.com/mSfHnSR
====== Ajax ======
function ex_go(r_idx)
{
if(confirm("Are you sure?") == true)
{
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});
$.ajax({
type:'POST',
dataType: 'JSON',
url: "{{ route('change-centerYn') }}",
data:{r_idx:r_idx},
success:function(data){
alert(data.success);
location.reload();
},
error:function(xhr, data){
console.log(xhr);
},
}else{
return false;
}
}
====== Controller ======
public function ex_ok(Request $request)
{
if(request()->ajax())
{
$r_idx = 'Hello';
var_dump('<pre>', $r_idx);
return response()->json(['msg'=>'Updated Successfully', 'success'=>true]);
}
}
Since you aren't using Try & Catch or error handling your controller will return 200 HTTP header status code, which means ajax will always think that process is correct and noting went wrong, try using error handling in your controller function and raise an exception if something went wrong during your code process. you can read at this link
you can see a sample code modification to your existing code below:
public function ex_ok(Request $request)
{
try
{
if(request()->ajax())
{
$r_idx = 'Hello';
var_dump('<pre>', $r_idx);
return response()->json(['msg'=>'Updated Successfully', 'success'=>true]);
}
}
catch(\Exception $e)
{
\Log::error($e); // create a log for error occurrence at storage/log/laravel.log file
return response()->json($e->getData(), $e->getStatusCode());
}
}
It's suddenly working! Unbelievable!
Thank you very much! You saved my morning!
Use try catch
========= AJAX ===========
function ex_go(r_idx)
{
if(confirm("해당 결제건을 지원센터로 보내시겠습니까?") == true)
{
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});
console.log(r_idx);
$.ajax({
type:'POST',
dataType: 'JSON',
url: "{{ route('change-centerYn') }}",
data:{r_idx:r_idx},
success:function(data){
alert(data.success);
location.reload();
},
error:function(xhr, data){
console.log(xhr);
}
});
}else{
return false;
}
}
========= Laravel Controller =======
public function ex_ok(Request $request)
{
try
{
if(request()->ajax())
{
$r_idx = $request->r_idx;
$lecture = DB::table('class_order')
->select('*')
->where('r_idx', '=', $r_idx)
->first();
if ($lecture->r_oid != '') {
$insert_data = [
'r_oid' => $lecture->r_oid,
'r_user_id' => $lecture->r_user_id,
'r_name' => $lecture->r_name,
'r_tel' => $lecture->r_tel,
'r_hp' => $lecture->r_hp,
'r_email' => $lecture->r_email,
'r_zip' => $lecture->r_zip,
'r_addr1' => $lecture->r_addr1,
'r_addr2' => $lecture->r_addr2,
'r_class' => $lecture->r_class,
'r_enddate' => $lecture->r_enddate,
'app_endday' => $lecture->app_endday,
'whole_study' => $lecture->whole_study,
];
DB::table('ex_class_order')->insert($insert_data);
ClassOrder::where('r_idx', '=', $r_idx)->update(['centerYn' => 'y']);
$info_txt = "처리되었습니다.";
}
else
{
$info_txt = "처리실패";
}
return response()->json(['msg'=>'Updated Successfully', 'success'=>true]);
}
}
catch(\Exception $e)
{
\Log::error($e); // create a log for error occurrence at storage/log/laravel.log file
return response()->json($e->getData(), $e->getStatusCode());
}
}
I am using hapijs version 17.0.1. I am trying to upload an image using ajax request on a hapijs route. Here is my AJAX code to upload profile pic:
var image_file_input = document.getElementById("user_profile_upload");
image_file_input.onchange = function () {
if(this.files != undefined)
{
if(this.files[0] != undefined)
{
var formData = tests.formdata ? new FormData() : null;
if (tests.formdata)
{
//alert(file)
formData.append('image_file', this.files[0]);
formData.append('userId', user_id);
formData.append('memberId', member_id);
}
$.ajax({
url: "/v1/User/uploadUserPic",
data: formData,
type: "POST",
dataType: "json",
contentType: false,
processData: false,
contentType: "multipart/form-data",
success: function(data){
console.log(data);
var errMsg = null;
var resData = null;
if(data.statusCode == 200)
{
resData = data.result;
}
else
{
alert(data.message)
}
},
error: function(error){
alert(error);
}
});
}
}
}
And here is my Hapijs route Code:
var uploadUserPic = {
method: 'POST',
path: '/v1/Module/uploadUserPic',
config: {
description: 'Update Image For User',
tags: ['api', 'User'],
auth: 'session',
payload: {
output: 'stream',
parse: true,
allow: 'multipart/form-data'
},
validate: {
payload: {
userId : Joi.string().regex(/^[a-f\d]{24}$/i).required(),
memberId: Joi.string().required(),
image_file: Joi.object().required(),
},
failAction: FailCallBack
}
},
handler: function (request, reply) {
var resultData = null;
var error = null;
return new Promise(function (resolve) {
var multiparty = require('multiparty');
var fs = require('fs');
var form = new multiparty.Form();
form.parse(request.payload, function (err, fields, files) {
if(err)
{
error = err;
resolve();
}
else
{
var mkdirp = require('mkdirp');
var img_dir = "./files/users/";
mkdirp(img_dir, function (err) {
if (err)
{
error = err;
console.error(err);
resolve();
}
else
{
var oldpath = files.image_file.path;
var newpath = "./files/users/"+requestPayload.userId+".png";
fs.rename(oldpath, newpath, function (err) {
if(err)
{
error = err;
}
resolve();
});
}
});
}
});
}).then(function (err, result) {
if(err) return sendError(err);
if(error) return sendError(error)
return {
"statusCode": 200,
"success": true
};
});
}
}
The above code gives me following error cannot read property 'content-length' of undefined on line form.parse(request.payload, function (err, fields, files) {});
Please let me know If I am doing something wrong. If I replace the url in ajax request with anohter url that I have written in php then it works perfectly. which means that something is wrong with my hapijs/nodejs code.
There's a good post on how to handle file uploads in Hapi.js (written in version 16) https://scotch.io/bar-talk/handling-file-uploads-with-hapi-js
Since you are using payload.parse = true, I am not seeing a particular reason why you have to use multiparty. I have the following working code that would save files (of any type) uploaded from client into uploads directory on the server (Please do not use directly on production as no sanitation is done)
{
path: '/upload',
method: 'POST',
config: {
payload: {
output: 'stream',
parse: true,
allow: 'multipart/form-data'
},
validate: {
payload: {
files: Joi.array().single()
}
}
},
handler: function(request) {
const p = request.payload, files = p.files
if(files) {
console.log(`${files.length} files`)
files.forEach(async file => {
const filename= file.hapi.filename
console.log(`Saving ${filename} to ./uploads`)
const out = fs.createWriteStream(`./uploads/${filename}`)
await file.pipe(out)
})
}
return {result: 'ok'}
}
}
You can use the following curl command to test
curl http://localhost:8080/upload -F 'files=#/path/to/a/note.txt' -F 'files=#/path/to/test.png' -vvv
There are a few issues with your code. First in your $.ajax call, you have specified contentType twice, although it's not a syntax error but it's careless to code like that. Second the function's signature inside your .then() block is incorrect. You are mixing the idea of Promise and callback. I don't think the following line will be triggered
if(err) return sendError(err);
One last trivial thing, you said you are using Hapi 17 but based on the handler function's signature
handler: function (request, reply) {
...
Seems you are not totally onboard with Hapi17 as the new signature is
handler: function (request, h) {
And it's not just the rename of reply to h.
I am trying to send a success status to the ajax request using res.end('{"success" : "Updated Successfully", "status" : 200}'); but run into this error: Error: Can't set headers after they are sent. Basically when the user data is saved on the server I want ajax to refresh the page, although, I think somewhere in this in the app.post a success message is being sent before I try to manually do it. How can I prevent any success message being sent to the ajax post request so I can do it manually.
app.post('/signup', function (req, res) {
var userDetails = User({
username: req.body.username,
email: req.body.email,
password: bcrypt.hashSync(req.body.password1, bcrypt.genSaltSync(10))
});
User.findOne({
$or: [{
'username': req.body.username
}, {
'email': req.body.email
}]
}, function (err, user) {
if (user) {
if (allClients.indexOf(req.body.socket)) {
if (user.username === req.body.username) {
io.to(req.body.socket).emit('userInfo', 'That username is already in use.');
} else {
}
if (user.email === req.body.email) {
io.to(req.body.socket).emit('userInfo', 'That email is already in use.');
} else {
}
} else {
console.log('timeout error 822')
}
} else {
req.login(userDetails, function (err) {
if (!err) {
userDetails.save(function (err) {
if (err) throw err;
res.end('{"success" : "Updated Successfully", "status" : 200}');
res.redirect('/');
});
} else {
console.log(err)
}
})
}
if (err) {
return done(err);
}
});
});
This is my ajax request
$("#form1").submit(function(e) {
e.preventDefault();
$.ajax({
datatype: "json",
type: "POST",
url: '/signup',
data: $(this).serialize(),
success: function(result)
{
console.log(result);
if(result.status == 200){
window.location.reload(true);
}
}
});
});
I think the problem is in the code:
res.end('{"success" : "Updated Successfully", "status" : 200}');
res.redirect('/');
Replace the above with only
res.status(200).send({"success" : "Updated Successfully", "status" : 200})
res.redirect is to take the user to another page(it calls a get route). The error you are getting is because node is confused between sending the response back to ajax or to redirect.
Looking at the Flux Documentation I can't figure out how the code to a ajax update, and a ajax fetch would fit into the dispatcher, store, component architecture.
Can anyone provide a simple, dummy example, of how an entity of data would be fetched from the server AFTER page load, and how this entity would be pushed to the server at a later date. How would the "complete" or "error" status of request be translated and treated by the views/components? How would a store wait for the ajax request to wait? :-?
Is this what you are looking for?
http://facebook.github.io/react/tips/initial-ajax.html
you can also implement a fetch in the store in order to manage the information.
Here is an example (it is a concept, not actually working code):
'use strict';
var React = require('react');
var Constants = require('constants');
var merge = require('react/lib/merge'); //This must be replaced for assign
var EventEmitter = require('events').EventEmitter;
var Dispatcher = require('dispatcher');
var CHANGE_EVENT = "change";
var data = {};
var message = "";
function _fetch () {
message = "Fetching data";
$.ajax({
type: 'GET',
url: 'Url',
contentType: 'application/json',
success: function(data){
message = "";
MyStore.emitChange();
},
error: function(error){
message = error;
MyStore.emitChange();
}
});
};
function _post (myData) {
//Make post
$.ajax({
type: 'POST',
url: 'Url',
// post payload:
data: JSON.stringify(myData),
contentType: 'application/json',
success: function(data){
message = "";
MyStore.emitChange();
},
error: function(error){
message = "update failed";
MyStore.emitChange();
}
});
};
var MyStore = merge(EventEmitter.prototype, {
emitChange: function () {
this.emit(CHANGE_EVENT);
},
addChangeListener: function (callback) {
this.on(CHANGE_EVENT, callback);
},
removeChangeListener: function (callback) {
this.removeListener(CHANGE_EVENT, callback);
},
getData: function (){
if(!data){
_fetch();
}
return data;
},
getMessage: function (){
return message;
},
dispatcherIndex: Dispatcher.register( function(payload) {
var action = payload.action; // this is our action from handleViewAction
switch(action.actionType){
case Constants.UPDATE:
message = "updating...";
_post(payload.action.data);
break;
}
MyStore.emitChange();
return true;
})
});
module.exports = MyStore;
Then you need to subscribe your component to the store change events
var React = require('react');
var MyStore = require('my-store');
function getComments (){
return {
message: null,
data: MyStore.getData()
}
};
var AlbumComments = module.exports = React.createClass({
getInitialState: function() {
return getData();
},
componentWillMount: function(){
MyStore.addChangeListener(this._onChange);
},
componentWillUnmount: function(){
MyStore.removeChangeListener(this._onChange);
},
_onChange: function(){
var msg = MyStore.getMessage();
if (!message){
this.setState(getData());
} else {
this.setState({
message: msg,
data: null
});
}
},
render: function() {
console.log('render');
return (
<div>
{ this.state.message }
{this.state.data.map(function(item){
return <div>{ item }</div>
})}
</div>
);
}
});
I hope it is clear enough.
I am sending a post request via AJAX. The data successfully posts but the AJAX call never completes. Backbone on the front; Node on the back. I am including the save function from my backbone view and the express route.
save: function(event) {
event.preventDefault();
console.log( 'You signed up for ' + this.model.get('name'));
var name = this.model.get('name');
var courseDay = this.model.get('courseDay');
var time = this.model.get('time');
var location = this.model.get('location');
jQuery.post("/test/signups", {
"name" : name,
"courseDay" : courseDay,
"time" : time,
"location" : location,
}, function (data, textStatus, jqXHR) {
console.log("Post response:");
console.dir(data);
console.log(textStatus);
console.dir(jqXHR);
});
}
Route:
app.post('/test/signups', isLoggedIn, function (req, res){
User.findOne({'_id': req.user.id }, function(err, user) {
if (err)
return done(err);
if (user) {
user.signup.name = req.body.name;
user.signup.courseDay = req.body.courseDay;
user.signup.time = req.body.time;
user.signup.location = req.body.location;
user.signup.modified = req.body.modified;
user.update({$push: { "signup" :
{ name: user.signup.name,
courseDay: user.signup.courseDay,
time: user.signup.time,
location: user.signup.location,
modified: user.signup.modified
}
}},{safe:true, upsert:true},function(err){
if(err){
console.log(err);
} else {
console.log("Successfully added" + user.signup);
}
});
}
});
});
Your server side code needs to send a response. Try something like below. Note I try to cover all cases of an error, user not found, and user found.
app.post('/test/signups', isLoggedIn, function (req, res){
User.findOne({'_id': req.user.id }, function(err, user) {
if (err) {
return res.status(500).send(err);
}
if (user) {
user.signup.name = req.body.name;
user.signup.courseDay = req.body.courseDay;
user.signup.time = req.body.time;
user.signup.location = req.body.location;
user.signup.modified = req.body.modified;
user.update({$push: { "signup" :
{ name: user.signup.name,
courseDay: user.signup.courseDay,
time: user.signup.time,
location: user.signup.location,
modified: user.signup.modified
}
}},{safe:true, upsert:true},function(err){
if(err){
return res.status(500).send(err);
}
console.log("Successfully added" + user.signup);
res.send(user);
});
} else {
res.status(404).send();
}
});
});