AJAX! Proper way to handle reponses

I have a simple form where a admin can change her/his password. In order to do so she/he needs to enter the old password and two times the desired new password. In order to make this work I have the following basic jQuery function:

$("document").ready(function(){
	$("#passwordForm").on("submit", function(e) {
		e.preventDefault();
        $.ajax({
			type: "POST",
            url: "/admin/page/change_password",
            data: $(this).serialize(),
            success: function(data){
				$("#passwordForm").find("input").val("");
				$("#passwordForm").fadeOut(500);
				$("#statusMessage").html(data).fadeIn(1000);
            }
        });           
	});
});

…and on the server side (PHP) I have the following:

$check			= $this->page->check_password($this->session->get('admin'));
$chk_password	= $check['admin_password'];
$old_password   = filter_input(INPUT_POST, 'old_password', FILTER_SANITIZE_STRING);
$new_password   = filter_input(INPUT_POST, 'new_password', FILTER_SANITIZE_STRING);
$rep_password   = filter_input(INPUT_POST, 'rep_password', FILTER_SANITIZE_STRING);
$has_password	= password_hash($wachtwoord, PASSWORD_DEFAULT);		
		
if (!password_verify($old_password, $chk_password ))
{
	echo 'Current password is not right! Try again';	
}
elseif (strcmp($new_password, $rep_password))
{
	echo 'Passwords did not match! Try again.';	
}	
else
{
	echo 'Password was successfully changed.';
	$this->page->update_password($has_password, $this->session->get('admin'));	
}

This is basically working fine when all requirements are met. I.e. The passwordForm fading out, the statusMessage fading in and the database update query is executed. But what if the requrements are not met? If the old password is not eq to the new entered password and if the new password and the repeat password fields do not match. In that case I obviously don’t want the passwordForm to fade out, instead only the input files needs to be reset

$("#passwordForm").find("input").val("");

What do I need to change in the success function to make that happen

Thank you in advance

Well #1: Do some validation on the sending end before you send it to the PHP engine. (Keep the validation at the PHP end also, because you never trust a client based validation, but.)
#2: Have PHP chuck a status other than 200 back. 400 would be good for this. Chucking an error code rather than 200 OK will trigger ajax to call error instead of success.

Hi, Thanks for the responce :slight_smile: Very much appreciated. Can you give an example of the last part:

I’m not sure what you mean?

Thx in advance

[fphp]http_response_code[/fphp]

$.ajax({
			type: "POST",
            url: "/admin/page/change_password",
            data: $(this).serialize(),
            success: function(data){
				$("#passwordForm").find("input").val("");
				$("#passwordForm").fadeOut(500);
				$("#statusMessage").html(data).fadeIn(1000);
            },
            error: function(response) {
                //Something bad happened. 
                console.log(response.status);
                console.log(response.responseText);
            }
        });

(I have omitted the two optional parameters for error’s function declaration, for sake of brevity)

@m_hutley Thx again for the reply. Excuse my ignorance but this is really confusing me! I use the if/elseif/else functions in order to determine if the requirements were met or not. Do you mean that I can add this to the error block

	$("#passwordForm").find("input").val("");
	$("#statusMessage").html(response).fadeIn(1000);
    console.log(response.status);
    console.log(response.responseText);

for those two conditions where the requirements were not met? Again sorry for the ignorance

The error block is just “Something went wrong, the URL i requested sent back an error code.” It’s not specific to “There was a password mismatch”.
What you’ve got there is almost fine (though i’d remove the debugging console.log’s in production code ;P). response is an xhr (jqXHR) object, so you should refer to response.responseText for the contents of the message PHP echoed out.

Alternatively, because you always want to do two of the three instructions, you could do it this way:

$.ajax({
			type: "POST",
            url: "/admin/page/change_password",
            data: $(this).serialize(),
            success: function(data){
				$("#passwordForm").fadeOut(500);
            },
            complete: function(response) {
                //Regardless of if it was successful... 
 				$("#passwordForm").find("input").val("");
                $("#statusMessage").html(response.responseText).fadeIn(1000);
           }
        });
1 Like

@m_hutley. That works great thanks a lot :+1:

Edit: I was cheering a bit to early. The passwordForm should only fade out if all requirements were met. Now it is fading out no matter what. Hope this make any sense

Have you actually told PHP to throw the different status code if something went wrong?

@m_hutley That is where I lost you in the first place :frowning: Sorry

Have your PHP call [fphp]http_response_code[/fphp] if it detects an error, feeding it the number 400.

@m_hutley Thank you for the patience :frowning: This (with the http_response_code) is completely new to me. Not sure where to start and where to finish. I have it temporary working though using the following in the jQuery function:

$("document").ready(function(){
	$("#passwordForm").on("submit", function(e) {
		e.preventDefault();
        $.ajax({
			type: "POST",
            url: "/admin/page/change_password",
            data: $(this).serialize(),
            success: function(data){
				if(data == "Password was successfully changed!") 
				{
					$("#passwordForm").find(".form-control").val("");
					$("#passwordForm").fadeOut(500);
					$("#statusMessage").html(data).fadeIn(1000);
				}
				else
				{
					$("#passwordForm").find(".form-control").val("");
					$("#statusMessage").html(data).fadeIn(1000);	
				}
            }
        });           
	});
});

But I guess that is very vulnerable and I would prefer to do it the right way

So. Basics of HTTP communication.
Every time you request a file, the response carries with it a status code.
Most times, that code is 200. Which means “OK”.
Things that start with 2 are success codes. (OK, Created, Accepted, etc)
Things that start with 4 are Client Error codes (Not Found, Unauthorized, etc)
Things that start with 5 are Server Error codes (Bad Gateway, Internal Server Error etc).
Additional Reading

PHP doesn’t have a conceptual idea that the password not matching is an error. Something being false is just… something being false. It processes its code, and if no PHP errors occur, it hands back whatever HTML you echoed out, with a status set to 200, because it successfully served the document, regardless of its content.
What we’re doing is telling PHP “If this happens, we want to set the status code to 400 instead”. Error Code 400 corresponds to Bad Request.

AJAX doesn’t inspect the contents of the result either. It determines whether the request was successful or not by the status code it receives. (Similar to PHP, if it receives a status 200, it successfully got a document. It doesn’t care what’s IN the document.)

1 Like

for example, here’s my Network screen when i load this page:


Notice that most of the status codes are 200. Which are fine. There’s a 307 in there, which indicates i’ve been redirected to get the file from elsewhere (the 200 code one directly below it, when the browser followed the redirect)
There’s also a couple of 0’s marked as flat out (failure). Which don’t translate to any status. Which is odd, but is probably an instance where something i’m running blocked the request (ad-blockers, antiviruses, etc can cause this)

1 Like

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.