Sunday, 4 December 2011

Keeping HTML design separated from code

The well-known part

Since Tridion 5.3 was born, we dived into Modular Templating. If you have seen our trainings on Modular Templating or if you have just read about best practices on this field, you'll probably know that we emphasize on the fact that modules should be built in a way that code and design are well separated. So if you are using Dreamweaver (DW) and .NET Template Building Blocks (TBB's), the DW should be kept simple and contain the HTML output while most logic should go into your C# code. This best practice keeps your templates neater and as a result more maintainable. For instance, if there is a simple change in the graphical design, only the DW modules will be affected; the C# code will stay untouched and there won’t be a need for recompiling it.

Okay, the first part of my story is clear. Let me step into my second point. There is one important consideration to make – what about those pieces of a website that involve some dynamism?

Where it can go wrong

In a lot of cases, the full html (or I could call it “the full puzzle”) cannot be generated at publishing time. We are then talking about front end functionality that will get executed at request time.
Examples of this dynamic functionality are the following: 
  1. Reading from generated xml files – i.e. Applications.xml
  2. Retrieving data from external sources – i.e. retrieving data from a product catalog.
  3. Language selector – i.e. display the languages where that page is available at the moment of request.
The result of the example functionalities from above could be:
  1. Data coming from the xml displayed as foldable headers and tables where every row represents an application version which is still supported.
  2. A price of a product retrieved from a product catalog
  3. A list of clickable languages using a specific html. The current language is selected in the list. There are no broken links nor empty items in the list.
Let me take a moment to get back to the initial part of my story:
We know that when creating Modular Templates, it is important to separate html output (DW) from complex logic (C# code). That is to say, we are trying to make our code independent from the HTML design. Great, but then, shouldn’t we do the same with the code we write for the web application?

The answer to this is clear: Yes! As much as possible! And this article gives you ideas on how to do it.

Going into details: Language Selector case

*** Case input ***

Business requirements:  The list of languages displayed in every page must also be up to date. That is to say, every page request must check in which other languages the current page is available. The current language must appear selected in the list.

Graphical design

*** Case solution ***

If our website runs on a .NET platform, custom controls could be used to deliver this dynamic functionality. This control would check the availability of the current page in the websites for the other existing languages. The current language is selected in the html.

Initially, the call to that control could look like:
<myTagPrefix:LanguageSelector  runat=”server”/>

The question is: how do we keep the code free of HTML output?
The key part of the solution is to feed the custom control with the html needed.

One of the ways to implement the solution is to provide the control with the necessary pieces of our html and also some placeholders.

Here is an example:
<myTagPrefix:LanguageSelector runat="server">
  <div class="combobox" id="lang-chooser">
   <div class="outside">
     <b class="toggle-box primary">
     <div class="inside">
     <b class="toggle-box secondary">
  <li class="checked"><a href="[URL]">[LANGUAGE_NAME]</a></li>
  <li><a href="[URL]">[LANGUAGE_NAME]</a></li>

Placeholders can be used to be replaced by dynamic values and to put the pieces together. In our example we have divided our html in three pieces – main structure with a placeholder and two repetitive patterns with two placeholders:

Main structure (MS): the html that creates the skeleton of the list. The final step of the control will replace the result accumulated out of iterating through the different languages and applying any of the repetitive patterns per language.

Current language pattern (CL): the control will use this html piece to display the current language in the list. The placeholders here must be replaced with the corresponding values for the given language.

Non Current language pattern (NCL): the control will use this html piece to display any language in the list that is not the current one. The placeholders here must be replaced with the corresponding values for the given language.

How will the code build up the final result? Two main steps:
  1. Build up the languages list without skeleton
  2. For every language x
    If current page is available in language x
    If language x is current language
    Use CL – replace placeholders with url and language name
    Add html result to temporary accumulated html
    Use NCL – replace placeholders with url and language name
    Add html result to temporary accumulated html
  3. Integrate languages list into skeleton structure
    Use MS – replace [LANGUAGES] with result from step 1.

Back now to .NET specifications, to access the three html nodes, you will just need to decorate every property like:
public string SelectorFormat { get; set; }
public string CurrentLanguageFormat { get; set; }
public string NonCurrentLanguageFormat { get; set; }
As a final note, the same idea is implemented by .NET templated controls. I won’t elaborate on that for now, but if you are interested in more information, these are two good links to start with: general information and an example.

1 comment:

  1. Indeed, it's tough finding maintainable ways to manage and provide "hooks" between the different Web development "tiers" (JavaScript, HTML, Code, Web service, SQL, CMS API, etc).

    I do wonder how well-known modular templating is (outside the immediate circle of consultants and techies). We definitely need more examples and good/best practices (hint hint).

    Also love the connection back to functional requirements!