Smartlet Architecture

Introduction

Smartlets are web page components that support 'dual rendering':

  1. They act like normal translations, so they can be rendered using the Viper syntax.
  2. They support rendering in 'Ajax callback mode', with the HTTP Request and Response Content-Type set to 'application/json'.

The Smartlet architecture is a building block for the Smartsite iXperion Web Toolkit. It depends on the Smartsite Client Framework, which includes a server component, the Smartlet macro. Smartlets macros can be used in the Smartlet (SML) ContentType. This ContentType is derived from TRA and has the ability of rendering Ajax/JSON callbacks for client updating.

The Smartlet macro

The Smartlet macro provides an abstraction layer for building Ajax-enabled translations. It provides a simple model for declaring public Smartlet properties and passing them around from client to server and vice versa using JSON over XmlHttpRequest.

Parameters

  • Properties
    Collection of public properties for the Smartlet. These will go over the line using JSON over Ajax
  • Xml (default)
    Generates the HTML for the Smartlet.

Extension Vipers

  • this.get(), this.get()
    Gets a named value
  • this.set(), this.set()
    Sets a return value into the return JSON when in Ajax callback mode.
  • this.id()
    The unique identifier of a Smartlet. Generated automatically if not specified.
  • this.Id(string elementId)
    The calculated id of an element within the Smartlet
  • this.isajaxcallback()
    Returns true if the Smartlet macro is executed during an Ajax callback.

Static Vipers

  • Smartlet.Parse(jsonString, ListOfStrings bufferNames[])
    Parses a json string and sets the given buffers.
  • All extension Vipers are also implemented as static Vipers that automatically match the Smartlet that is in scope. 

My first Smartlet

Let's beef things up with some useless sample material.

The textarea below will load data from the server on first focus:

Smartsite SXML CopyCode image Copy Code
<se:smartlet>
 <se:parameters>
  <se:parameter name="properties">
   <se:collection>
    <se:member name="text">Click here to load...</se:member>
    <se:member name="url" state="both" type="locator" >http://www.nu.nl/</se:member>
   </se:collection>
  </se:parameter>
  <se:parameter name="xml">
   <se:if expression="smartlet.isajaxcallback()">
    <se:then>
     {smartlet.set(text, string.readfromurl(smartlet.get(url)))}
    </se:then>
    <se:else>
     <se:placeholder.addjavascriptonload>
      var el = document.getElementById('{smartlet.id()}');
      el.firstChild.onfocus = function(){
       if(el.loaded) return;
       var sml = System.Smartlet.get(el);
       sml.ajax(function(){
        el.loaded = true; 
        el.firstChild.value = sml.get('text');
       });
      };
     </se:placeholder.addjavascriptonload>
     <div class="LateLoadTextbox" id="{smartlet.id()}">
      <textarea rows="25" cols="80" name="txtBody">{smartlet.get(text)}</textarea>
     </div>
    </se:else>
   </se:if>
  </se:parameter> 
 </se:parameters>
</se:smartlet>

Or, using JQuery's one() method, that adds a single shot event handler:

Smartsite SXML CopyCode image Copy Code
<se:smartlet>
 <se:parameters>
  <se:parameter name="properties">
   <se:collection>
    <se:member name="text">Click here to load...</se:member>
    <se:member name="url" state="both">/assets/behavior/classes/smartlet.js</se:member>
   </se:collection>
  </se:parameter>
  <se:parameter name="xml">
   <se:if expression="smartlet.isajaxcallback()">
    <se:then>
     {smartlet.set(text, string.readfromfile(smartlet.get(url)))}
    </se:then>
    <se:else>
     {placeholder.addjavascriptinclude('/assets/scripts/jquery.js')}
     <se:placeholder.addjavascript>
      $(document).ready(function () {
          $("textarea").one("focus", function(){
        var sml = System.Smartlet.get('{smartlet.id()}');
        var t = this;
         sml.ajax(function(){
         $(t).text(sml.get('text'));
        });
       })
      });
     </se:placeholder.addjavascript>
     <div class="Textbox" id="{smartlet.id()}">
      <textarea rows="25" cols="80" name="txtBody">{smartlet.get(text)}</textarea>
     </div>
    </se:else>
   </se:if>
  </se:parameter> 
 </se:parameters>
</se:smartlet>

Creating a Smartlet

  • Ensure that you have installed the client-side prerequisites in the Scf folder under the Web Root:
    /scf/jquery/jquery.js and /scf/jquery/jquery.scf.js
  • Ensure that your Render Templates include a call to <se:scf /> just after the mandatory placeholders.
  • Create a CMS folder with a describing name for the Smartlet
  • Add a Smartlet (SML) item and provide it with a name and Smartlet macro replacement.
  • Add CSS and Javascript items in the same CMS folder: they will automatically be included when the Smartlet is executed.

The client side

The /scf/jquery/jquery.scf.js script is written as an jQuery extension and manages the client side state of all Smarlets and provides an easy way to access both client- and server side Smartlets, through the object $j.scf.smartlet.

As you can see in the examples, the code used to get access to the client side Smartlet is:

HTML CopyCode image Copy Code
var smartlet = $j.scf.smartlet.get(id);

Then, the code to access the server side Smartlet:

HTML CopyCode image Copy Code
smartlet.ajax(callbackFunction);

callbackFunction then is a function pointer that will be called  after the roundtrip. The original Smartlet variable will then be updated with new state from the server.

The smartlet.set() and smartlet.get() methods can be used to set parameters before a roundtrip and retrieve state after:

HTML CopyCode image Copy Code
smartlet.set('day', div.innerText);
smartlet.ajax(function(){alert(smartlet.get('agenda'))});

In fact, one of the essential parts of the Smartlet architecture is the fact that server and client manipulation are seemlessly compatible.

Debugging client side logic

Obviously, tools like Fiddler and Firebug can help identifying problems in JSON traffic over XmlHttpRequest, but the Smartlet library also exposes a simple debug handler that will be called at several stages of the transport:

HTML CopyCode image Copy Code
$j.scf.smartlet.debug({
  write: function(x){
    alert(x);
  }
});

 

Topics