Multi screen ajax updates/Custom view engine
Update multiple tiles at once

In the simple ajax tutorial we started an ajax implementation. It has one draw back. You can only update one part. However you probably want to update more than one part.

Page=
whole page
First part to update
Second part to update

How to do this. Well there are many ways to do this. So I will be describing my implementation. This tutorial starts where the simple ajax tutorial stops. Oke, let's start.
During the processing of the Action we will gather the views to update. I created a couple of extension methods to collect the updates. The updates are stored on the call context. An update is a tile intended for updating only a part of the page. This is discusses in the previous tutorial. An new view engine is created to generate a view containing all parts to update. After the Ajax.Updater is finished all individual parts are processed. Processing means replacing the target div with the new div and execute the contained javascript.

Let's look at an Update methods in ViewEngineExtensions class

public static Controller Update(this Controller controller, string forId, string viewName, object model)
{
  var view = MultiViewEngine.GetMultiView()1;
  view.Add(
    forId2,
    new TilesView(viewName)3,
    new ViewDataDictionary(model)4
  );
  return controller;
}

  1. The multi view stored on the call context. If not present one is created.
  2. The id of the div to update.
  3. The view to update.
  4. The model to use during rendering.

The other "Update"-extension methods do basicly the same, but have slight variations in arguments. I created two more extension methods.

public static ViewResult Render1(this Controller controller)
{
  return new ViewResult
    {
    ViewData = controller.ViewData,
    ViewName = controller.GetTilesViewName(),
    TempData = controller.TempData,
    };
}

public static ViewResult RenderLayout2(this Controller controller)
{
  return new ViewResult
  {
    ViewData = controller.ViewData,
    ViewName = "LayOut",
    TempData = controller.TempData,
  };
}

  1. The "Render" method renders all parts in a generated view. This should be called after all "Update"-calls
  2. The "RenderLayout" method renders the layout with the stubs, divs, to update.

These methods depend on a custom view engine the MultiViewEngine.class. The MultiViewEngine.class basicly contains some plumbing code to get some basics done. The MultiViewEngine handles ...

  1. Placing the MutliViewResult on the call context and cleaning up after all parts are rendered
  2. Rendering a layout view(empty frame which can be filled with updates) or an update view with changed parts

public ViewEngineResult FindView1(
      ControllerContext controllerContext,
      string viewName,
      string masterName,
      bool useCache)
{
  if(viewName.Equals("LayOut"))
  {
  return new TilesViewEngine().FindView(
    controllerContext,
    viewName,
    masterName,
    useCache);
  }
  var view = GetMultiView();
  return new ViewEngineResult(
      view,
      this
    );
}

public static MultiView GetMultiView2()
{
  var view = (MultiView) CallContext.GetData("View");
  if(view==null)
  {
    view = new MultiView();
    CallContext.SetData("View", view);
  }
  return view;
}

public void ReleaseView2(
  ControllerContext controllerContext,
  IView view
){
  CallContext.SetData("View", null);
}

  1. Generate a multi view or the layout view
  2. Administration of the MultiView on the CallContext

Now we move on the the interesting code the MultiView.class. This is the class where all updates are rendered in the one generated view.

private readonly IList _parts = new List();

public void Render(ViewContext viewContext, TextWriter writer)
{
  foreach (var part in _parts)
  {
    viewContext.ViewData = part.Data;
    writer.WriteLine(string.Format(
        "<div id=\"update-{0}\">", part.ForId)1

    );
    part.View.Render(viewContext, writer)2;
    writer.WriteLine(string.Format("</div>"));1
  }
}

public void Add(string forId, IView view, ViewDataDictionary data)
{
  _parts.Add(new PartialView{ForId = forId, View=view, Data=data});
}

public class PartialView
{
  public String ForId { get; set; }
  public IView View { get; set; }
  public ViewDataDictionary Data { get; set; }
}

So what is happening here. When the multiview is rendered all registered updates, tiles, are rendered.

  1. The rendered part is wrapped in side a div with an id indicating which div should be updated.
  2. The part, a tile, is rendered.

This covers the server side. The client side requires some javascript to make this work. I changed the goto(url) method to handle the view returned by the MultiView

String.prototype.startsWith = function(str){
return (this.match("^" + str) == str) }

function goto(url)1{
new Ajax.Updater('pageUpdate', url,
{ method: 'get', onComplete: updatePage2 });
}

function updatePage()2
{
  var update = $('pageUpdate');
  $('pageUpdate'). childElements().each3(
    function(child)
    {
      var id = "" + child.identify();
      if (id.startsWith("update-"))
      {
        var idToUpdate = id.substr(
          "update-".length,
          (id.length - "update-".length)
        )4
;
        $(idToUpdate).replace($(id))5;
        $(id).id = idToUpdate6;
        $(idToUpdate).addClassName('blink')*;
        setTimeout(
          "removeBlink('" + idToUpdate + "')",
          1000
        )*;
      }
    }
  );
  runScripts()7;
}

function removeBlink(id)
{
  $(id).removeClassName('blink');
}

function runScripts()7()
{
  var injections = $$('.javascriptInjection');
  injections.each(
    function(injected)
    {
      eval(injected.innerHTML);
      injected.remove();
    }
  );
}

It's a lot of code at once. However it doesn't do that much. Walk over all parts. Extract the id to update . Update the div with that id. And run all the new javascript.

  1. Place the call to the server.
  2. And register the updatePage method to process the multiview.
  3. Process each part in the update
  4. Extract the id to update(target)
  5. Update the target
  6. Restore the id of the target
  7. Run the javascript we injected in the page. The javascript is not embedded in <script/> but in a hidden div with class ".javascriptInjection". This solves some issues with browser not allowing script replacement.

*=You can ignore this blink stuff. It's only there to show what was updated. I added it for the tutorial.

Well this is basicly it. If you miss something in the explanation. Just post me a mail with your question in the contact form.

Contact form fixed

I regret reporting that the contact form was broken for the last week. All mails send to us were corrupted(empty). So reported bugs in the last week are not received. I'm aware that the timing with regards to the monorail release isn't very handy. The contact form is fixed now. I apologize.

4 February, 2010

Monorail released M5

Monorail is released. The release also contains some minor fixes.

23 January, 2010

Monorail almost finished

Maikel Willemse is coding a Monorail view engine. It's available in the nightly release. A tutorial and a new release will be available shortly.

2 January, 2010

No more tiles.xml
(if you like)

A NSTL view engine is now available. You can do SharpTiles without having a tiles.xml. You will lose the power of dependency injection. If you are interested check out the tutorial page.

21 July, 2009

Developer M3 released

Fixed a couple of parse bugs. Cleaned up refreshing of resources, resource locations and registration of the TilesViewEngine. Wrote some tutorials
Ronald Dehuysser contributed the <tiles:insertTemplate/> and <tiles:putAttribute/> tag.

8 June, 2009

HtmlHelper wrapped II

Updated tag reference documentation.

5 April, 2009

Ready for MVC RC 2

SharpTiles is now ready to use with MVC RC 2.

6 March, 2009

HtmlHelper wrapped

The MVC HtmlHelper is now wrapped and can be used. For it's only available in the nightly build. When the documentation and new Tutorials are made a new release will be made.

22 December, 2008

Ready for Beta 1

SharpTiles is now ready to use with MVC Beta 1. The tutorial page will be updated soon.

3 November, 2008

We've got Tiles

It took me a bit longer than expected but Milestone 1 is reached. Tiles are now available.

23 July, 2008

First release

Finally, after some hard work my pet project is ready for its initial release. Here it is! Please give it some thoughts and feel free to add comments.

23 May, 2008

SID: PopUp 0