1

I have a registration form. The PHP is checking for errors such as short password
AJAX gives an alert with the echo error from PHP.

With PHP, after an if else statement,
the user will be registered and redirected successfully to index.php (good)

header('Location:home.php');
exit;

The problem is, if there is any error, the user will be redirected to handler.php and the echo alert shows there (on white page)

var form = document.querySelector('.register form');
form.onsubmit = function(event) {
    event.preventDefault();
    var form_data = new FormData(form);
    var xhr = new XMLHttpRequest();
    xhr.open('POST', form.action, true);
    xhr.onload = function() {
      document.querySelector('.msg').innerHTML = this.responseText;
    };
    if (xhr.status >= 200 && xhr.status <= 299) {
      var response = JSON.parse(xhr.responseText);
      if (response.location) {
        window.location.href = response.location;
      } else {
        xhr.send(form_data);
      }
    }

Example 2: the alerts will display properly at <div class="msg"></div> position
(But will also throw the index.php on registration form, where the alerts go)

var form = document.querySelector('.register form');
form.onsubmit = function(event) {
  event.preventDefault();
  var form_data = new FormData(form);
  var xhr = new XMLHttpRequest();
  xhr.open('POST', form.action, true);
  xhr.onload = function() {
    document.querySelector('.msg').innerHTML = this.responseText;
  };
  xhr.send(form_data);
};

So, i want the user to be redirected to index.php & also the alerts to be handled by AJAX

  • Simple, don't respond with redirects for async requests. Let the client-side handle navigation in those cases – Phil Nov 05 '21 at 04:07
  • Also, `if (xhr.status >= 200 && xhr.status <= 299) { ... }` should be within the `onload` callback – Phil Nov 05 '21 at 04:09
  • ... though `xhr.send()` should not be – Phil Nov 05 '21 at 04:15
  • Thank you, Phil. Could you please show me the complete solution? I been researching this over 30 hours with no solution, started learning js/ajax so is hard to understand – contributor01010 Nov 05 '21 at 04:18
  • I read it, It makes sense but i don't know how to code/implement this. Simply ``if (xhr.status >= 200 && xhr.status <= 299)`` from what i understand is the success response, then ``window.location.href`` to redirect to ``Location:home.php`` (which came from PHP) – contributor01010 Nov 05 '21 at 04:39
  • _either a 200 (success) or an error status like 400 (bad request) + error details. The client can navigate to home on success or display error information otherwise_ >> I understand, but how can i implement this with code? Thanks for your time Phil – contributor01010 Nov 05 '21 at 04:40

1 Answers1

1

Regarding responding to AJAX requests with redirects, please see What is the difference between post api call and form submission with post method?. Does a better job explaining than I could.

The basic idea is that when called asynchronously, your PHP should do what it needs to do and respond with either a 200 (success) or an error status like 400 (bad request) + error details.

// make sure nothing is echo'd or otherwise sent to the
// output buffer at this stage

$errors = []; // collect errors in here

// do whatever you need to do with the $_POST / $_FILES data...

// capturing errors example...

if ($_POST['cpassword'] != $_POST['password']) {
    $errors[] = "Passwords do not match!";
}

// use content negotiation to determine response type
if ($_SERVER['HTTP_ACCEPT'] === "application/json") {
    if (count($errors)) {
        header("Content-type: application/problem+json");
        http_response_code(400);
        exit(json_encode([
            "message" => "Invalid form data or something",
            "errors" => $errors
        ]));
    }

    header("Content-type: application/json");
    exit(json_encode(["location" => "home.php"]));
}

// just a normal request, respond with redirects or HTML
// ...

foreach ($errors as $error) : ?>
    <div class="error"><?= $error ?></div>
<?php endforeach;

The client can navigate to home on success or display error information otherwise

document.querySelector(".register form").addEventListener("submit", async (e) => {
  e.preventDefault()

  const form = e.target

  const body = new FormData(form)

  // fetch is much easier to use than XHR
  const res = await fetch(form.action, {
    method: "POST",
    headers: {
      accept: "application/json", // let PHP know what type of response we want
    },
    body
  })

  const data = await res.json()

  if (res.ok) {
    location.href = data.location
  } else if (res.status === 400) {
    document.querySelector('.msg').textContent = data.message
    // also do something with data.errors maybe
  }
})
Phil
  • 157,677
  • 23
  • 242
  • 245
  • I see what you going for. Im studying the thread + your code, please update the PHP syntax, Thank you Phil. – contributor01010 Nov 05 '21 at 04:55
  • 1
    @contributor01010 _"please update the PHP syntax"_... sorry, I don't know what that means. _Ed:_ ah, I had a couple of syntax errors. I don't write PHP anymore, can you tell – Phil Nov 05 '21 at 04:57
  • No worries! Im still studying all the basics so this is tremendous help! Appreciate your time to contribute, i'll check again tomorrow and mark as solved when done. Take care! :) – contributor01010 Nov 05 '21 at 05:07
  • By the way each 'errors' are handled like this in php, ``if ($_POST['cpassword'] != $_POST['password']) { exit('Passwords do not match!'); }`` how do i approach, based of the example above? – contributor01010 Nov 05 '21 at 05:15
  • I'll add an example but you cannot `echo` anything prior to the content-negotiation – Phil Nov 05 '21 at 05:21
  • i tried your solution over the past 4 hours and there are errors or it doesn't work correctly, this is my [handler.php](https://pastebin.com/Q1QSWPjd) (for registration) How would you add your snippet in this? – contributor01010 Nov 05 '21 at 18:27
  • sorry im new with both php & ajax so it's hard to deal with. appreciate your time & efforts – contributor01010 Nov 05 '21 at 18:28
  • Perhaps you should just use an entirely different PHP file for async requests if your current one makes it difficult to work with – Phil Nov 05 '21 at 21:46