Monday, November 2, 2009

PURE Version 2 and truly dynamic table rendering.


I would like to build a dynamic data-driven Web application.
There is a set of data records and I would like full control over its presentation during the run-time, i.e. customized.

I came across the Beebole' PURE Version 2 rendering engine, which was immediately gaining on me after I made some attempts with the first version of Pure. Here is the short demo just to prove the concept:


The complete code is placed at BitBucket to play with.

The idea: I was scrolling through the Beebole examples (selecting jquery there) and the Example #5, "Dynamic Table", had double rendering in it. It was a bit sad when I noticed the columns were pre-defined in the rendering directive and JSON structure was used only for the record rendering:
var ex05 = {
 template:'table.partialTable',
 data:{
 cols:['name', 'food', 'legs'],
 animals:[
 {name:'bird', food:'seed', legs:2},
 {name:'cat', food:'mouse, bird', legs:4},
 {name:'dog', food:'bone', legs:4},
 {name:'mouse', food:'cheese', legs:4}
 ]
},
 directive1:{
 'th':{
    'col<-cols':{
    '.':'col'
    }
  },
 'td':{
 'col<-cols':{
   '@class':'col'
  }
 }
}, 
directive2:{
  'tbody tr':{
     'animal<-animals':{
        'td.name':'animal.name',
        'td.food':'animal.food',
        'td.legs':'animal.legs'
      }
   }
}
As you can see, the rendered table will always have name, food and legs columns, and there is no control by JSON over it. Well, a little upgrade and it all gets resolved.
var ex05 = {
 template:'table.partialTable',
 data:{
     cols:['name', 'food', 'legs'],
     animals:[
        {name:'bird', food:'seed', legs:2},
        {name:'cat', food:'mouse, bird', legs:4},
        {name:'dog', food:'bone', legs:4},
        {name:'mouse', food:'cheese', legs:4}
     ]},
 directive1:{
    'th':{
          'col<-cols':{
          '.':'col'
          }
     },
    'td':{
       'col<-cols':{
       '@class':'col'
       }
     }
 }, 
 directive2:{
  'tbody tr':{
     'animal<-animals':{ // loop over all records
        'td': { 
            'col <- cols': {  // take each column in cols
               '.': recValue, // td value will be a result of call to recValue
               '@class':'col' // optional line - the class of  will be the col value from the loop
      }
   }
}
// the standard arg has an item property and all the context: arg.animal.item is current external loop value (records) 
function recValue(arg){
   return arg.animal.item[arg.item];
}
What is going on here? The external loop, animal <- animals places into the animal object the records one by one. For each record, the internal loop by col <-cols gets created. The recValue function gets called with the argument arg, being an object which contains information on both loops. The arg.item carries the running col value. The arg.animal.item carries current animal value. So what left is to get the right value of the animal property, using the col value - that is what the recValue does. So, we have the generic HTML and JavaScript code which uses only "cols" and "animals" names, but the stuff inside JSON will determine what the table will display.