I have an ASP.NET MVC 4 application that has one section that behaves like a SPA. It's a page with multiple steps and, because I'm working sessionless, I'm sending from the client to the server (using AJAX) the ID of the entity in every request (I'm also sending a GUID that needs to correspond to the ID in order to be valid, this is for detecting data tampering). Let's say that the user is on step 3 and one of the following things happen: 1) An error occurs: I have a global filter that inherits from HandleErrorAttribute that logs the error and sends an email, and after all, it shows a custom error page. The problem is that if the user press the browser's back button, the hidden fields are lost and the process has to start from step 1 again. 2) The user navigates away from the page. I think that I can warn the user with a dialog.
Thanks in advance.
EDIT:
I'm showing a warning dialog when the user wants to navigate away.
$(window).bind('beforeunload', function () {
if ($("#id").val() != "") {
return 'If you leave the page, the offer will be lost.';
}
});
If after he navigates away presses the browser's back button, I'm redirecting him to the first step of the flow because the previous entered data is lost.
if ($("#id").val() == "" && window.location.hash != "") {
window.location.hash = "";
}
It sounds like your AJAX request for the next step is hitting a Controller action that's redirecting you to a new page. That's fine, and it's good you're keeping your server code stateless by sending up all the relevant information back up to the Controller for each step. However, doing it this way means that you're stuck using the custom error page, and you're going to have trouble making that work well with your setup.
My suggestion: move more towards a true SPA. When I visit Step1, the Controller should send back a whole page (like you're doing). Let's assume that this page has a container like <div id="step-container"> ... HTML for each step is in here ... </div>
.
Now, when you click the button to move on to step 2, instead of hitting the controller action expecting to get redirected to a new page, send out an AJAX request for a Partial View with the Step 2 content.
On the server, change your Step2.cshtml
from a regular view to a Partial View (you can make a new View and click the Partial View checkbox), and for convention's sake, you should probably rename it _Step2.cshtml
. In your Controller action public ActionResult Step2(... data)
, you could change your return statement to return PartialView("_Step2")
, but leaving it as return View("_Step2")
is just fine.
Now for the important part, the client. Here, you're issuing an AJAX request for that Partial View.
// Set the data from your form in this variable
var data = { };
// Issue a GET request out to the controller action. Make sure the URL is right
$.get('/Steps/Step2', data)
.done(function(result) {
// This promise will execute when we get the content of the Partial View back from the server
// The result variable should have the HTML for the view
// Use jQuery to set the content in your step div to the new HTML
$('#step-container').html(result);
})
.fail(function(error) {
// This promise function will execute if there is an error in the Controller
// and it returns something other than a 200 type response code
// Handle the error here, maybe showing a dialog or trying to fix the error
alert('Sorry, form submission failed');
});