What’s All the Todo About?

The Navigation for ASP.NET project makes building Single Page Applications easy. Just divide up your Razor views into panels and the Navigation project will use changed panel content from the server to update the innerHTML of corresponding elements on the client. The self-appointed SPA police would have us believe that this isn’t a legitimate technique for building Single Page Applications, but my TodoMVC implementation says otherwise.
Creating a todo
Some parts of TodoMVC seem impossible to build using this technique. Take creating a todo as an example, where, once created, the new todo is appended to the list. How’s it possible to single out the new todo’s HTML on the server? And which client element will hold this new todo’s HTML so that it appears in the list?

Spot the Difference

We’ll start on the server by dividing up our Razor view so that each todo is inside its own panel.

<ul id="todo-list">
@foreach (var todo in Model.Todos) {
    <li>
        @Ajax.RefreshPanel("todo" + todo.Id,
            (context, fromData, toData) => true,
            @<div>
                <!-- Todo details -->
            </div>)
    </li>
}
</ul>

The RefreshPanel Extension method accepts a Func that indicates whether the content has changed. Because only changed content is sent to the client, if that Func only returned true for the newly created todo our job would be done. So the Func needs access to the newly created todo id and our Controller can provide this by storing it in the HttpContext.

(context, fromData, toData)  
	=> (int?) context.Items["todoId"] == todo.Id

Draw a Blank

There isn’t a corresponding element on the client to hold the HTML, but if we can create an empty element in the list with a matching id before the Navigation logic runs then all will be well. The Navigation project’s JavaScript Api exposes an updating event that fires early enough where we can extract the id from the response panel passed in and create the new list item.

refreshAjax.updating(function (req, resp) {
	var panelId = Object.keys(resp.panels)[0];
	var todoList = document.getElementById('todo-list');
	todoList.insertAdjacentHTML('beforeend', 
		'<li><span id="' + panelId + '" /></li>');
});
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s