I am new to Promises and I am sure I am doing something wrong with my code.
The result is correct but I have an Uncaught (in promise) warning in my console.log.
What is going on here is the User can submit a form where there are some required fields, some optional fields and an image.
On submit I am getting the image that gets compressed, resized and oriented so that it upload to the server as a small amount of Kbs.
In the coontroller I validate the code as said, some fields are required so in the error case inside the Ajax call I get the textStatus if a field is missing.
What happens with this code is that if the user inputs the image but none or some of the required fields the XHR textstatus error object appears as Uncaught (in promise), (The missing required fields).
I am missing the point of how you deal with errors (reject ? ) in promises so I don't really know how to solve this one.
My guess is that if the User submits the image but not the required fields there should be a way to check that during the promise so that it gets rejected even if the user submitted the image (as the image alone does not suffice). Is this done with reject ? But where? and how do you call the error after .then() ?
And what if the user submits some required fields or all of them but not the image? If I let the promise run I get an undefined error in the promise, that's why I added a check to see if there's any file and if it's an image.
This is my script:
$(document).ready(function () {
$("#AddModel").on("submit", function (e) {
e.preventDefault();
// gets the file from the form input
var files = $('#modelpic').prop('files');
var form = $(this);
// this strips the submitted form from the file and returns a new form with all the
// inputs but the file
var processedFormData = noFileFormData(form[0]);
// only if there's a file and it's an image
if( files.length !== 0 && /^image/.test(files[0].type)){
//this calls the promise that manipulates the image and returns a blob
processImage(files[0]).then(([img, ia])=> {
processedFormData.append('image', ia, 'processed.jpg');
return $.ajax({
type: 'POST',
url: form.prop('action'),
processData: false,
contentType: false,
cache: false,
data: processedFormData,
success: function (data) {
//displays preview of the post
},
error: function (textStatus) {
//displays errors
}
});
});
}else{
//displays an error re the image is not present.
// Now this is not optimal as the image is not the only required field
}
});
});
This is the promise function that prepares the manipulated image, it calls some other functions for the real processing:
function processImage(file) {
return new Promise(function (resolve, reject) {
if (file.type.match('image.*') && file.length != 0) {
var reader = new FileReader();
reader.readAsDataURL(file);
reader.onloadend = function () {
var base64img = this.result;
var exif = EXIF.readFromBinaryFile(base64ToArrayBuffer(this.result));
var srcOrientation = exif.Orientation;
resetOrientationResizeCompress(base64img, srcOrientation).then((img)=> {
dataURItoBlob(img).then((ia)=> {
resolve([img, ia]);
});
});
};
}else{
//don't really know what to do here really, or if this is the way
reject();
}
});
}
It is telling you that you are not catching the error rejection, append .catch to the processImage(files[0]) promise.
Related
I have a standard form with fields. One of those fields is a file upload. The form is processed via ajax and in the success block, IF there are attached files, I need to make another ajax call to upload the file. This is where I'm struggling. If an upload needs to be done, I execute the if/ block, perform ajax, then on ajax success, redirect. In the /else block, I don't need to perform any ajax, so I can immediately redirect. I don't like having this redirect twice as it is not DRY. I know I can instead use a function in each of these places, then only have the redirect once, but that still seems to violate the DRY standard since I'm still calling the function twice.
Is there a better way to write this?
if (files.length > 0) {
readFile(files[0],function(filestring){
var fileObj = new Object();
fileObj.file = filestring.split(";base64,")[1];
fileObj.fullFileName = document.getElementById("file").files[0].name;
fileObj.fileName = fileObj.fullFileName.split(".")[0];
fileObj.ext = fileObj.fullFileName.split(".")[1];
fileObj.leadid = resp.leadid;
doAjax(fileObj,endpoints.file).then(function(resp){
window.location.href = "returnURL";
});
});
}else{
window.location.href = "returnURL";
}
I cannot think of a better/cleaner way to write this and I am not sure how to search for this on Google, since I'm not sure what the correct terminology would be to describe this problem.
In case you need to see it, here is the doAjax function.
function doAjax(data,url){
return $.ajax({
url: url,
cache: false,
method: "post",
dataType:"json",
data: data
});
}
Here is the readFile function
function readFile(files,callback){
var reader = new FileReader();
reader.readAsDataURL(files);
reader.onload = function (e) {
callback(reader.result);
}
reader.onerror = function (error) {
console.log('Error: ', error);
};
}
How about something like this?
doAjax = function(files, endpoints) {
if (files.length > 0) {
readFile(files[0], function(filestring) {
var fileObj = new Object();
fileObj.file = filestring.split(";base64,")[1];
fileObj.fullFileName = document.getElementById("file").files[0].name;
fileObj.fileName = fileObj.fullFileName.split(".")[0];
fileObj.ext = fileObj.fullFileName.split(".")[1];
fileObj.leadid = resp.leadid;
return resp;
});
}
return [];
}
doAjax(files, endpoints).then(function(resp) {
window.location.href = "returnURL";
});
EDIT:
I was reading your post again, уоu say The form is processed via ajax and in the success block, IF there are attached files, I need to make another ajax call to upload the file The question is, where do you perform validation? Validation has to be done along with the form on the server side. A hacker may be able to upload files without the having success back from the server. This is best done using one call, уоu send the attached files (if they exist), validate the form, if success then уоu store the files, if not then уоu throw an error, then redirect the user when уоu get the response whether they attached files or not.
Using Axios this would look something like this:
let form_data = new FormData();
form_data.append('data_to_validate', data);
if (files.length > 0) {
form_data.append('attachment', myFiles.files[0]);
}
axios({
url: '/api',
method: 'post',
data: form_data,
headers: {'content-type': 'multipart/form-data'}
})
.then(response => {
window.location.href = response.returnURL;
})
.catch(error => {
});
Good day guys. In my laravel application I'm trying to check if attendence for a particular date, subject, grade exists in my table. If so I have an if statement setup to display desire results based on what is returned.
I'm making the request with ajax but it seems like ajax keeps running the error function and I don't seem to get any error code whatsoever or internal server error(500, 404, 403, etc) In my console the status return is 200 ok
here is my script:
$(document).on('change', '#subject', function(event) {
event.preventDefault();
/* Act on the event */
var subject = $('#subject').val();
var grade = $('#grade').val();
var date = $('#date').val();
if (subject != "" && grade != "") {
$.ajax({
url:"/attendence/students",
method:"GET",
data:{"subject_id":subject, "grade_id":grade, "date":date},
dataType:"json",
success:function(data){
$("#result").html(data);
},
error:function(){
$("#result").html('There was an error please contact administrator');
}
});
}
});
Here is the controller the request is send to:
public function students(Request $request)
{
//
$grade = Grade::findOrFail($request->grade_id);
$subject = Subject::findOrFail($request->subject_id);
$students = Student::where('grade_id', $grade->id)->get(['id', 'first_name','middle_name', 'surname', 'grade_id']);
$statuses = Attendence::statuses();
// this check if attendence has been setup for the given date.
// if so prevent user for enter another date
$attendenceExists = Attendence::where([
'grade_id' => $grade->id,
'subject_id' => $subject->id,
'date' => $request->date
])->first();
if ($attendenceExists) {
return response()->json('A recorded attendence already exists for the seleced grade and subject!');
}
else {
return \View::make('attendence.partials.attendence-form')->with(array(
'students' => $students,
'subject' => $subject,
'date' => $request->date,
'statuses' => $statuses
));
}
}
Now, if this code returns true:
// this check if attendence has been setup for the given date.
// if so prevent user for enter another date
$attendenceExists = Attendence::where([
'grade_id' => $grade->id,
'subject_id' => $subject->id,
'date' => $request->date
])->first();
if ($attendenceExists) {
return response()->json('A recorded attendence already exists for the seleced grade and subject!');
}
The condition here runs and the right result is returned. But my else statement in the above does run but I don't get the right result. This is the result I get:
There was an error please contact administrator
Which shows that it is this part of the ajax request that is running:
error:function(){
$("#result").html('There was an error please contact administrator');
}
Surprisingly when I check the console this is what I see:
Which is exactly what I want but ajax is return otherwise. Am I doing something wrong?
Your dataType is set to json while you're returning html. Change it to html.
$.ajax({
url:"/attendence/students",
method:"GET",
data:{"subject_id":subject, "grade_id":grade, "date":date},
dataType:"json",
statusCode: {
200: function(data) {
$("#result").html(data.responseText);
};
}
}
});
Try this. I hope this will help you
I would say don't set the dataType at all. Just remove that setting altogether and let the jQuery ajax() method detect it automatically for you. That way, if the response type is JSON, it'll work. If the response type is HTML, it'll also work. 👍🏻
Right now, I have a form with several fields and on submit, I want to check if the username is taken or not. If taken, do nothing (show validation error), if not taken, successfully proceed onto the next form.
Here's what I have done so far:
View:
var RequestCreateAccount_Submit = function () {
var res = false;
ValidationAttribute.BlankValue(true);
var form = $('form#RequestCreateAccount');
$.validator.unobtrusive.parse(form);
var res = form.valid();
var data = form.serialize();
if (res) {
$.ajax({
url: Url.getFullUrl('Account/RequestCreateAccount_Submit'),
type: 'Post',
data: data,
cache:false,
success: function (data) {
//Next Dialog
},
error: AjaxLog.HandleAjaxCallFail
});
}
return res;
}
Controller:
[AllowAnonymous]
[HttpPost]
public ActionResult RequestCreateAccount_Submit(UserAccount userAccount)
{
//Check if username is unique
if (!WebSecurity.UserExists(userAccount.UserName))
{
UserSession.AddValue(StateName.CreateOrEditAccount, "CurrentUserAccount", userAccount);
JsonResult res = Json(new { Success = true, data = "", Message = "" });
return res;
}
JsonResult jres = Json(new { Success = false, data = "", Message = "Username is already registered"});
return jres;
}
I tested it with a known username and it did hit the success=false (outside of the if statement) line and it did not go inside the if statment. So I know the validation on the server side works.
However, I am wondering why on the client side, it still success = true and the next dialog appeared. It did not fail on validation. What am I doing wrong on the client side?
The reason is that your controller does actually successfully return a result. It is just that the successful result indicates an error. While logically similar at this point, they are very different. Error is going to be reserved for actual exceptions thrown or 404 no route present type of scenarios.
You should check for the response status inside of your success callback function
dotNetFiddle Demo
$.ajax({
url: Url.getFullUrl('Account/RequestCreateAccount_Submit'),
type: 'Post',
data: data,
cache:false,
success: function (data) {
if(data.Success === false){
AjaxLog.HandleAjaxCallFail();
// this may not make as much sense though
// as the request didn't actually fail, just the action did
//TODO: code for name fail
return;//do not process next dialog
}
//Next Dialog
},
error: AjaxLog.HandleAjaxCallFail
});
The success = false of your result object doesn't means that the request failed. It stands only for data.success, nothing more. The resquest is still successful(HTTP 200), which I think is the right response code. If you return an error code like new HttpStatusCodeResult(404, "error message"); it means that your request failed, but it isn't true.
You request works whatever the result of the check is. So you may check this in your success callback, instead of the error callback:
success: function(data) {
if (data.success) {
//Next Dialog
}
else {
// error message
}
}
I use Prototype.js to validate a form. For one of the fields, I have the prototype script ajax a request to a file. The file is a simple PHP file and will return '1' if the value is OK and '0' if the value is not OK. I have the script as below, which should work perfectly. The prototype validation is supposed to show a validation error message when a field does not pass validation, and not display / remove the message once the field passes validation. But in this case, even when the ajax file returns '1', the validation will display the error message anyway. Anyone able to help would be greatly appreciated!
['validate-number3', numessage3, function(v) {
new Ajax.Request('test.php?nr='+v, {
method:'get',
onSuccess: function(transport) {
var response = transport.responseText;
if(response == '1'){return true;}else{return false};
}
});
}],
the return value from Ajax.Request is the Ajax.Request object and returns as soon as the request is setup - the onsuccess callback is called after the request has been completed - so checking the results of Ajax.Request is not useful for what you want to accomplish.
The reason that this doesn't work as you expect, this is an asynchronous call which means it will start the call and then return control to the script while it is processing and then run the callbacks when it is completed.
Try it this way
new Ajax.Request('test.php?nr='+v, {
method:'get',
onSuccess: handleResponse
});
function handleResponse( transport ){
var response = transport.responseText;
if(response == '1'){
//everything is OK
}else{
//value is not OK
};
}
I was able to solve my question!
Thanks to this teriffic page: http://inchoo.net/ecommerce/magento/magento-frontend/magento-form-field-ajax-validation/ it was no problem. This is what I ended up with:
var ok = false;
new Ajax.Request('test.php?nr='+v, {
method:'get',
asynchronous: false,
onSuccess: function(transport) {
var response = transport.responseText;
if(response == '1'){ok = true;}else{ok = false;};
},
onComplete: function() {
if ($('advice-validate-number-pay_bank_no')) {
$('advice-validate-number-pay_bank_no').remove();
}
}
});
return ok;
I am using dojo forms and submitting using AJAX. I use 2 methods of validate: on client side and on server side:
dojo.connect(form, "onsubmit", function(event){
dojo.stopEvent(event);
var digit_form = dijit.byId("user_profile_form");
if (!digit_form.validate()) {
return false;
}
// client-side validation is ok, so we submit form using AJAX
var xhrArgs = {
form: form,
handleAs: "json",
load: function(responseText){
// here I get response from server
// and if there are errors on server
// responseText object contains array with errors, so I
// need to show this errors to user
},
error: function(error) {
}
}
var deferred = dojo.xhrPost(xhrArgs);
}
The problem is that validate() method shows nice error messages to user, but when I get errors from server I can't show errors like method validate() does, so I use native javascript alert() method that is not so nice. I would like equal displaying of errors that validates on server and client side.
For each server side error, set a new widget.SSError property.
error: function(error) {
widget.set('SSError','The value is invalid because server thought so...'
form.validate();
}
Override the widget.isValid() function and make it check the new widget.SSError property.
Based on this message,
var myCustomFS = dojo.declare(dijit.form.FIlteringSelect, {
postMixInProperties: function() {
this.inherited(arguments);
// Point _isValidOld at the function isValid currently points at
this._isValidOld = this.isValid;
// Point isValid at a new function
this.isValid = function() {
if (this.SSError) {
return false;
}
return this._isValidOld(); // Calls the original isValid function
}
}
};
Put a watch on the value and reset widget.SSError when it changes.
widget.watch('value', function(){
widget.set('SSError', false)
})