MonoRail & Ajax Generators
I mentioned that MonoRail recently aquired Ajax Generators. The generators a are different from normal templates, because they do not generate html, but rather modify the page that was already rendered. It will be easier to exaplain with an example. Let us take the simple example of paging a grid without a full post back, shall we? By the way, this turned out to be a lot more focused at the WebForms than I intended, more on that later.
Here is the backend of this demo:
public void Index(bool isAjax)
{
PropertyBag["subjects"] = PaginationHelper.CreateCachedPagination(
this, Action,15,delegate
{
return new List<Subject>(Repository<Subject>.FindAll()).ToArray();
});
if(isAjax)
RenderView("index.brailjs");
}
Simple, get the items from the database and store it in the cache, as well as passing it to the view. For now, please ignore the last two lines...
Now, let us a look at our view, shall we? There is a layout that I will not touch now (if you don't understand MonoRail terms, think about it as a MasterPage), but let us focus on the action's view index.brail:
<script type='text/javascript'>
function error(e)
{
alert(e);
}
function paging(index)
{
var url = '/faq/index.rails';
var pars = 'page=' + index +'&isAjax=true';
new Ajax.Request(url,{method: 'get', evalScripts: true, parameters: pars, onException: error});
}
</script>
<h2>Subjects for questions:</h2>
<div id='paginatedGrid'>
<?brail OutputSubView('grid') ?>
</div>
What we have here is merely a bit of javascript and a div to put the gird in. We also use OutputSubView for the grid (again, if WebForms terms, this is something like a UserControl). The most complex part is the grid.brail view itself:
<?brail
component GridComponent, {'source':subjects}:
section header:
?>
<th id='header'>Id</th>
<th id='header'>Name</th>
<th id='header'>Browse</th>
<?brail
end
section item:
?>
<tr id='item'>
<td>${item.Id}</td>
<td>${item.Name}</td>
<td>${ HtmlHelper.LinkTo('Browse','faq','showQuestions', item.Id) }</td>
</tr>
<?brail
end
section alternateItem:
?>
<tr id='alternateItem'>
<td>${item.Id}</td>
<td>${item.Name}</td>
<td>${ HtmlHelper.LinkTo('Browse','faq','showQuestions', item.Id) }</td>
</tr>
<?brail
end
section link:
?>
<a href='/faq/index.rails?page=${pageIndex}'
onclick='paging(${pageIndex});return false;'>${title}</a>
<?brail
end
end
?>
The GridComponent is somewhere in the middle between GridView and Repeater, since it can do almost everything on its own, but let you override (for isntnace, alternateItem) parts of the rendering in place. Please pay some attention to the last section, the link. This is a pagination link that can be used to override the default behavior of moving to the next page. I am overriding it with a
Now that we have established the page, we can play with it a bit, and see that it is working great. Except that there is still the last piece of the puzzle, paging without refreshing the full page.
Go check the javascript in index.brail, notice that it is making an Ajax request to /faq/index.rails ? And that it is passing isAjax=true? No go and check the Index() method, and look at the last two lines. If this is an Ajax request, we use a different view for the output, index.brailjs;
page.ReplaceHtml('paginatedGrid', {@partial : 'faq/grid' })
page.VisualEffect('Highlight', 'paginatedGrid')
Now, what is going on here... this certianly doesn't look like any ajax framework I have ever seen...
Remember that I spoke about the ajax generators? This is it. You may think about is as a small DSL for generating the javascript to modify the page. What we have here is a call to ReplaceHtml, which will replace the content of the paginatedGrid element with something else, usually a string. But, in this case, we pass in a @partial (@symbol is identical to :symbol in Ruby, but this is a temporary syntax at the moment, I want to get rid of the {} ), which means that we ask to replace the element with the results of running the grid template. The second line is just to provide some feedback to the user that something has changed. So, in essense, it took 4 lines of code to
But why invent a whole new syntax just to use ajax? Isn't Javascript enough? More on that next post...
Comments
Comment preview