Enabling Auto Save

At this point we have a dynamic template binding to our model and updating in real-time.  We also have the ability to add new items to the board.  However, you may have noticed that our changes don't "stick"; when you reload the page they are lost.  It turns out that saving changes, also in real-time, is very simple.  There are two main options for saving changes the user has made.

1) Save when a button or link is clicked.

<a href="#" onclick="context.server.save(context.model.user); return false;">Save</a>

2) Automatically save periodically.

context.server.startAutoSave(context.model.user, 1);

We're going to go with the second option.  For an app that aims to provide a smooth desktop-like experience, this is the logical choice.  The user won't have to think about saving, since the save occurs almost instantaneously.

Both code snippets above reference a "context" variable.  You may remember from the Bind to Model section that the context variable was used to store the root object of our model query, the user.  The context object is also used to control client-server interaction, via its "server" property.

In both cases the first argument is the root object to save.  This can be any object that has been loaded on the client.

In the case of auto-save, the second argument is the amount of time to wait after a change is detected before saving changes.  Like window.setTimeout or window.setInterval, the unit of time is milliseconds.  Using a value of 1 has the effect of saving changes after the browser's event loop completes.

With auto-save enabled we can now add items and see that they "stick" after reloading the page.  But the process is pretty magical and we could potentially leave the page while in the middle of saving.  We'll add a status message at the top of the board when changes are being saved, and also warn the user before leaving the page if their changes haven't yet been saved.

In order to display status we'll subscribe to a few events, also found on context.server.

The full list:

For simplicity we will use the generic "Request" events.

Event Result
requestBegin Show a "working..." status.
requestEnd Hide the "working..." status.
requestSuccess Briefly show a "Success!" status.
requestFailed Show a "Failed!" status and provide a way to try again.

And here's the code to accomplish that:

context.server.addRequestBegin(function () {
         $(".board:not(.sys-template) .board-server-working").show();
});
context.server.addRequestEnd(function () {
         $(".board:not(.sys-template) .board-server-working").hide();
});
context.server.addRequestSuccess(function () {
         $(".board-status-save").hide();
         $(".board:not(.sys-template) .board-server-failure").hide();
         $(".board:not(.sys-template) .board-server-success").show().fadeOut(2000);
});
context.server.addRequestFailed(function () {
         $(".board-status-save").show();
         $(".board:not(.sys-template) .board-server-success").hide();
         $(".board:not(.sys-template) .board-server-failure").show().fadeOut(2000);
});
 
$(document.documentElement).on("click"".board-status-save"function () {
         $(".board-status-save").hide();
         context.server.save(context.model.user, function () {
                 context.server.startAutoSave(context.model.user, 1);
         });
});

And here's a screenshot of the status in action:

Next, we'll ensure that all changes have been saved before the user leaves the page.  To do that we'll subscribe to the browser's "beforeunload" event.  The event handler can return a string which is used, in some form or another, to prompt the user whether they really want to leave the page.  To determine whether there are changes that have not been saved we will use one final method of the server object, context.server.changes().

$(window).bind("beforeunload"function () {
         // Prompt the user if they will lose unsaved changes by navigating away from the page
         if (context.server.changes(false, context.model.user, true).length > 0) {
                 return "Are you sure you want to leave the page? You will lose unsaved changes.";
         }
});

And the result in Google Chrome:

 


  1. Insert the following snippet into Views\Home\Index.cshtml, in the main board markup, after the board-addlist element:
    <span class="board-status">
    	<span class="board-server-working">Communicating with the server...</span>
    	<span class="board-server-success">Success</span>
    	<span class="board-server-failure">An error occurred!</span>
    	<a href="#" onclick="return false;">Try again</a>
    </span>
    				
  2. Create the javascript file board-auto-save.js under scripts
  3. Insert the following snippet into scripts/board-auto-save.js:
    $exoweb({
    	contextReady: function (context) {
    		// Automatically save changes immediately
    		context.server.startAutoSave(context.model.user, 1);
    
    		// Update status when communicating with server
    		context.server.addRequestBegin(function () {
    			$(".board:not(.sys-template) .board-server-working").show();
    		});
    		context.server.addRequestEnd(function () {
    			$(".board:not(.sys-template) .board-server-working").hide();
    		});
    		context.server.addRequestSuccess(function () {
    			$(".board-status-save").hide();
    			$(".board:not(.sys-template) .board-server-failure").hide();
    			$(".board:not(.sys-template) .board-server-success").show().fadeOut(2000);
    		});
    		context.server.addRequestFailed(function () {
    			$(".board-status-save").show();
    			$(".board:not(.sys-template) .board-server-success").hide();
    			$(".board:not(.sys-template) .board-server-failure").show().fadeOut(2000);
    		});
    
    		$(document.documentElement).on("click", ".board-status-save", function () {
    			$(".board-status-save").hide();
    			context.server.save(context.model.user, function () {
    				context.server.startAutoSave(context.model.user, 1);
    			});
    		});
    	}
    });
    
    $(window).bind("beforeunload", function () {
    	// Prompt the user if they will lose unsaved changes by navigating away from the page
    	if (context.server.changes(false, context.model.user, true).length > 0) {
    		return "Are you sure you want to leave the page? You will lose unsaved changes.";
    	}
    });
    				
  4. Append the following code snippet in Views\Home\Index.cshtml under the list of script references:
    <script src="@Url.Content("~/scripts/board-auto-save.js")"></script>