Selective view rendering in Web Applications

Sunday, November 7th, 2010|Brainstorming, Version 3, Version 4|by Romans

Today – any desktop software is able to re-draw itself from a callback by operating system. However many Web Frameworks today do not keep track of objects and cannot selectively produce pieces of HTML code.

I believe that ability to have control over objects on HTML pages is very essential to have in the Framework. Here is why:

Desktop software

Early DOS applications sometime 1990 relied on quite straightforward method to display output on the screen. Whenever data became available, certain areas on display were updated. Program assumed that content of the screen remains the same always, and it only updated parts which were changed.

Unfortunately, if anything happened to the screen, the program were not aware of that, because the logic to “redraw” didn’t exist.

With the introduction of windowing systems applications learned to draw themselves in layers. Drawing now were completely independent from the execution of the software and were performed on-demand. For example if you overlap windows and move them, the bottom window would call redraw method to restore parts of the screen erased by the top window.

Web Software – still in 90-ties.

The similar things happen today in Web Applications. Most of the applications I have seen follow this pattern:

  1. They figure out which page / class / view you are trying to access. This class is loaded.
  2. They figure out which template the class will be using. They load template.
  3. Template contains includes and handling of the data.
  4. Once template is processed it’s outputted into parent’s template and when HTML is ready it’s sent to browser.

Because of this approach initialization of the objects, data loading and rendering is all combined making it impossible for the framework to control rendering process. It is also possible that objects are being destroyed after they rendered the output. Here is a sample code which illustrates the approach.

[php]

<?php
class Widget {
function render(){
$data=$this->prepareData();
return applyTemplate($data);
}
}
echo "<html><body>";
$widget=new Widget();
echo $widget->render();
echo "</body></html>";
[/php]

Better approach – two-pass walkthrough.

The approach which is used in Agile Toolkit (and it’s predecessor ¬†AModules2) separates process of initialization from the process of rendering. Here is what happens:

  1. Framework figures out which page / class / view user needs to access. Class is loaded.
  2. Framework figures out which template must be used.
  3. Object initialization is performed
  4. —- once the initialization is done recursive rendering is done —-
  5. Each object renders child objects and output is placed into it’s own template
  6. Top-level object renders it’s template and outputs it to the browser.

Here is a sample code which illustrates the approach:

[php]
class AbstractView {
public $elements=array();
function init(){
// do nothing yet..
}
function add($class){
$obj = new $class();
$this->elements[]=$obj;
return $obj;
}
function render(){
$output=”;
foreach($this->elements as $obj){
$output.=$obj->render();
}
return $output;
}
}
class Page extends AbstractView {
function init(){
parent::init();
$this->add(‘LoremIpsum’);
}
}
class LoremIpsum extends AbstractView {
function render(){
return "Lorem Ipsum Dolor Sit Amet";
}
}
class Api extends AbstractView {
function init(){
parent::init();
$this->add(‘Page’);
}
function render(){
echo parent::render();
}
}
[/php]

We have introduced a new class – AbstractView, which contains 3 methods: init() , render() and add(). This becomes a library class and it handles the tracking of objects. It’s no longer a problem of developer to controls hierarchy.

If you never used this approach before, then there are few things you should need to know:

Initialization and Rendering logic separation

There are 2 different methods in each class now. One determines how object is initialized or what it contains. Other determines how the object will look. Here is a brief look at some standard objects and how this separation works for them:

  • Grid
    • init: determines list of columns and format. Defines table name. How many records per page.
    • render: fetches data. Formats data.
  • Form
    • init: defines list of fields and their formats. Determines submit action. Validation rules. Data source.
    • render: Fetch data from source. Recursively render fields.
  • API
    • init: determines which page must be displayed. Adds this page. Initialize all other objects.
    • render: renders all other objects. Place their HTML into global template.

Depending on the situation you either will want to re-define init() or render().

Keeping track of object hierarchy is essential

With introducing method add() which automatically links children with parents. This makes sure that rendering of children can be automated for most of objects.

Why two pass is better?

You might say – “yes, separating render() makes sense for desktop, but not for web”. Actually – it does make sense. Primarily it keeps to clean your source up. But there are 2 other benefits:

Performance of AJAX applications

This makes perfect sense if you are using AJAX and you are willing to re-load part of your page. All you need to do is to perform normal initialization then locate the object you need and render only that object. If you place your heavy data-pulling procedures inside render() then most of them will NOT be called during your AJAX requests.

This helps a lot with performance.

HTML awareness

Finally – your framework now knows what is it on your page. It can grab the HTML for any object completely automatically. You as developer do not need to worry about outputting partial data.

Mix in – JavaScript

Several JS libraries (such as jQuery) suggest that you should not put JS into your HTML. Similarly to CSS it should be separately applied to your HTML after it have been loaded.

If you teach your framework to recognize which JavaScript code is meant for each object, you can also selectively apply different pieces of JavaScript depending of what’s being rendered.

Mix in – Template Engine

It is extremely easy to add functionality into init() and render() to support template handling. Inside init() you need to specify which template to use, and where data should appear in parent’s template. Inside render() you should perform rendering of the template.

Agile Toolkit does this

What I have described here is the initial idea inside Agile Toolkit. The idea itself is very old and well-established. It have been used since 2003. However only in 2009 support for JavaScript was added, which now integrates seamlessly.

Demo: Reloading with AJAX

http://demo.atk4.com/demo.html?t=5

This demo places two buttons which send AJAX request to the PHP framework. Those sub-requests have additional GET argument (cut_object):

http://demo.atk4.com/demo.html?t=5&cut_object=ATK_demo_tabs_Demo_grid&g=M

In response, framework will render only specified object with additional arguments.

Demo: JavaScript awarness

http://demo.atk4.com/demo.html?t=22

In this demo, when you click Edit button, the form is being re-loaded. If you look into inspector / firebug, you will see that a couple of javascript lines relevant to the form are being also sent to the frontend. However javascript related to the table is stripped off. This functionality is very essential when it comes to loading pieces of HTML which needs dynamic functionality.

Agile Toolkit which is using for implementation performs transparent handling of JavaScript – as developer you only need to define JS bindings once and they will be sent when relevant part of the page is being displayed.

Future thoughts

I have developed several FastCGI applications which were incredibly fast. This was thanks to a separation of initialization code and code which processed each request.

Normally PHP does not allow for a single execution of a script to handle multiple requests. However if you want to play with multi-request processing in PHP, consider this:

  1. init method initializes business logic.
  2. render method reads GET/POST and outputs data

As a result you might be able to call init() only once and then perform multiple render() calls to either full tree or only selective objects.

Do you have any ideas or suggestion? Comment below

2 Comments

Mastodont
Posted November 9, 201011:55 am

… if you are using AJAX … perform normal initialization then locate the object you need and render only that object. …

Separate controller for Ajax requests is IMHO much better.

romans
Posted November 9, 20101:21 pm

Strong point towards proposed approach is – you write less code.

But how exactly is having separate Ajax controller better?