Building fragments programmatically

classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|

Building fragments programmatically

Alexandre Roger
I would like to use Thymol to implement a simple client side search engine. I have a javascript database (lokijs) that returns javascript objects. I would like to take these objects and merge them with thymeleaf templates through thymol.

I would imagine something similar to :
var content = thymol.merge("template-name::fragment-name", variables)
$("#destination").html(content);

Or maybe even :
thymol.inject("#destination", "template-name::fragment-name", variables)
(if any efficiencies could be gained from not passing by a variable)

Is something like that possible? If not, could you give me a hint at where to look at in the code to implement such functionality?

Thank you in advance!
Reply | Threaded
Open this post in threaded view
|

Re: Building fragments programmatically

jjbenson
Administrator
Hi Alexandre,

  If I understand it correctly, you want to create templates dynamically and have Thymol process them as normal? Great question!

  The easiest way to approach this is to insert templates as pre-parsed DOM structures diredctly into the template cache.

  Here is an example:

    thymol.configurePreExecution( function() {
      var template = "<td>hello world!</td>";  
      var content = $.parseHTML(template);  
      if( !thymol.thCache ) {
        thymol.thCache = {};
      }    
      if( !thymol.thCache[ "product03a" ] ) {
        thymol.thCache[ "product03a" ] = {};
      }    
      thymol.thCache[ "product03a" ][ "productTemplate" ] = content[0];
    });

  So you can now do something like:

   <td th:include="product03a::productTemplate"/>

  Please post back your findings, these are very interesting ideas.

  Kind Regards,

    Jim
Reply | Threaded
Open this post in threaded view
|

Re: Building fragments programmatically

Alexandre Roger
Hi Jim! Thank you for your quick response.

The template-cache loading is very interesting but what is missing for me is how to merge a template fragment with a variable, programmatically from an event (let's say a button click). My template should not be merged at page load time, but as the user interacts with the page.

 Exemple :

HTML
  <button onclick="search($('query')">search</button>
  <input type="text" id="query"></input>
  <div id="replaceMe"></div>
Template
  <th:block th:each="${object : objects}" th:object="${object}">
    <label th:text="${role}">role</label><span th:text="${name}">name</span>
  </th:block>
and the application's javascript :
function search(query) {
  var results = find(query);
  // results now contains : {objects : [ {name: "Alex", role : "user"}, {name : "Jim", role : "developer"} ] };
  
  // this method doesn't exist yet, how do I go about it?
  thymol.insert($('#replaceMe'), 'product03a', results)
}

So the page gets rendered (with or without thymol), and once it's generated the user fills in the query field and presses the search button. The search() loads up a resultset in some way (I use a javascript database) and then displays the results by merging them with the templates.

Right now, I've made some progress by injecting a template into the dom and then calling thymol.execute(document):
function search(query) {
  var objects = find(query);
  // objects now contains : {objects : [ {name: "Alex", role : "user"}, {name : "Jim", role : "developer"} ] };
  
  $('#replaceMe').html(template);
  thVars = [['objects', objects]];
  thymol.execute(document)
}

It does replace the template with content, but it doesnt seem to work completely. I'm not sure yet if it's because of problems with my template or because I just can't call execute after the page has already been loaded.

Any help or hints will be very appreciated!
--
Alex
Reply | Threaded
Open this post in threaded view
|

Re: Building fragments programmatically

jjbenson
Administrator
Hi Alex,

  Thymol variables are held in map-like objects called "contexts" similar to the well-known (JEE style) ones, namely: applicationContext, sessionContext and requestContext.

  To add variables programmatically use the context's createVariable method: thymol.applicationContext.createVariable etc.

  Template instances have locally scoped variables that are associated with the (template instance) root element by a "monkey-patched" map-like object called "thLocalVars":

        newElement = <cached node>.cloneNode( true );
        newElement.thLocalVars = <parent element>.thLocalVars;

  You can added instance specific values like so:

        newElement.thLocalVars[ "extraVar" ] = <extra variable value>;
 
 "with" objects can similarly be added to newElement.thObjectVar

  If you add variables to the thLocalVars object before you render in Thymol, the template should respect those values.

  To "render" programmatically you can call the thymol.processChildren method:

        thymol.processChildren( {
          thDoc: <your root element>
        } );

  This will render new Thymol elements and attributes "in place".

  Thymol attributes (and thBlock elements) that are successfully rendered are removed from the DOM, so repeated calls should have no effect.

  You are using the correct entry point:

      thymol.execute( <your document> )

  This is the right thing to do, but it's intended to be called only when processing a document for the first time. I would suggest using this once (on document load) and calling thymol.processChildren to update the DOM on demand.

  Please let me know how you get on.

  Kind Regards,

   Jim