Sharing Server side and Client side templates

Often when creating a module or gadget you will want to render something server-side, then as the module loads with JavaScript, update the html with the new data/logic.

This presents a few questions:

- will the data load once, or refresh?
- is the data already embedded in the page?
- could the data take time to load?
- will we know that before creating our module?

- if data is coming from a javascript ajax request, will the html be empty until it loads?
- should we show a loader icon while this is happening?
- what if the server wants to render the module with some data and not load a feed?
- do we need a server-side template and then a javascript template

So many questions that prevent us from completing our module, and potentially could also force us to make changes to it later down the line as the functionality changes. I've come across this problem many times and come to a great solution.

Sharing server-side and client-side templates
Your html template should be the same for both server-side and client-side which means you need to pick the same library for both or implement the same custom template code. For this example i'm going to be using:

- Jinja for python,
- Twig for php
- Twig.js for JavaScript

A normal html file with div for javascript to attach to, javascript template and data would look something like this:

Main.html

<div id="list1" class="list"></div>


<script id="tmpl" type="text/template">
    <ul>
        {% for item in items %}
            <li><a href="{{ item.url }}">{{ item.name }}</a></li>
        {% endfor %}
    </ul>
</script>

<script>
    var list1 = new List('list1', [{'name': 'Item 1', 'url': 'http://www.google.co.uk'}]);
</script>


This is bad because html is combined with javascript script tags. The key is to separate the two cleanly.

Main.html
<div id="list1" class="list">
    {% include 'html/modules/Item.html' %}
</div>
<script id="tmpl" type="text/template">
    {% include 'html/modules/Item.html' %}
</script>


<script>
    var list1 = new List('list1', [{'name': 'Item 1', 'url': 'http://www.google.co.uk'}]);
</script>



List.html

  <ul>
  {% for item in items %}
    <li><a href="{{ item.url }}">{{ item.name }}</a></li>
  {% endfor %}
  </ul>

Now you can keep three files for each module which makes developing really easy:
List.html
List.css
List.js

Automated modules
Patterns start to emerge from writing our code this way, which allows us to automate processes. Lets output the modules dynamically:

Main.html

{%
    set modules = [
        { 'name': 'List', 'id': 'list1', 'data': [{'name': 'Item 1', 'url': 'http://www.google.co.uk'}] },
        { 'name': 'List', 'id': 'list2', 'data': [{'name': 'List 1', 'url': 'http://www.google.com'}] }
    ]
%}

{% for item in modules -%}

    <div id="{{ item.id }}" class="list">
        {% include 'html/modules/'~item.name~'.html' %}
    </div>
    <script id="tmpl" type="text/template">
        {% include 'html/modules/'~item.name~'.html' %}
    </script>


    <script>
        var {{ item.id }} = new {{ item.name }}('{{ item.id }}', {{ item.data }});
    </script>
{% endfor -%}

By outputting automatically you can keep all of your modules consistent while developing and ensure the all conform to the same structure.

An added benefit is that your backend developer can use you object to create the model for the CMS. He has all of the fields that the view requires to be rendered.

Saves a world of pain too when the data needs to be updated via ajax instead of server side.




No comments:

Post a Comment