Subscribe to RSS Feed

There is bunch of various possibilities how to generate UI using Domplate (remember entire Firebug UI is generated using Domplate - i.e. content of all panels) and so here is another set of how to examples that is trying to reveal some other useful aspect and patterns. Of course, all examples can be explored using Domplate Runner again.

See all posts about Domplate here.

Enjoy! 😉

How to generate a TABLE from 2D array

This example shows how to iterate two-dimensional data (using two nested loops) and generate corresponding HTML TABLE.

.myTableCell {
    padding: 5px;
    text-align: center;
}
var tableData = {
  rows: [
    {values: [1,2,3,4]},
    {values: [11,22,33,44]},
    {values: [111,222,333,444]},
  ]
};
var template = domplate(
{
  table:
      TABLE({border: "1"},
        TBODY(
          FOR("row", "$data.rows",
              TR(
                  FOR("value", "$row.values",
                      TD({class: "myTableCell"},
                          "$value")
                  )
              )
          )
        )
      ),
});

template.table.replace({data: tableData}, parentNode, template);

How to dynamically compose value of a class attribute

This example shows two ways how value of a class attribute can be dynamically generated.

  1. expression: $brand|getBrandClass is replaced by a value returned from getBrandClass method
  2. expression: $myFaforite: "$brand|isMyFavorite" inserts additional class name myFaforite into the class attribute if isMyFavorite method returns true
.carBrand {
  font-weight: bold;
}

.myFaforite {
  color: red;
}

.brand-Ford {
  color: green;
}
var inputData = ["Honda", "Chevrolet", "Toyota", "Ford", "Pontiac",
    "Dodge", "Mazda", "Nissan", "Volkswagen", "Hyundai"];
var template = domplate(
{
  tag:
    DIV(
      FOR("brand", "$carBrands",
        DIV({class: "carBrand $brand|getBrandClass",
             $myFaforite: "$brand|isMyFavorite"},
          "$brand"
        )
      )
    ),

  isMyFavorite: function(brand) {
    return (brand == "Nissan");
  },

  getBrandClass: function(brand) {
    return "brand-" + brand;
  }
});

template.tag.replace({carBrands: inputData}, parentNode, template);

How to use custom iterator in a FOR loop

This example shows how a custom iterator function can be implemented for a FOR loop. The FOR loop always expects an array to be iterated. In case when the input data isn't an array we can provide it using a function.

var searchResult = {
  title: "corvete.jpg",
  summary: "Chevrolet Corvette",
  url: "http://www.vu.union.edu/~jaquezk/MG/corvette.jpg",
  clickUrl: "http://www.vu.union.edu/~jaquezk/MG/corvette.jpg",
  RefererUrl: "http://www.neiu.edu/~ssalas/FramePage.htm",
  FileSize: 103936,
  FileFormat: "jpeg",
  Height: 768,
  Width: 1024,
};
var template = domplate(
{
  tag:
    TABLE(
      TBODY(
        FOR("member", "$object|getMembers",
          TR(
            TD("$member.label"),
            TD("$member.value")
          )
        )
      )
    ),

  getMembers: function(object) {
    var members = [];
    for (var p in object)
      members.push({label: p, value: object[p]});
    return members;
  },
});

template.tag.replace({object: searchResult}, parentNode, template);

How to build a tree

This example shows how to build an HTML tree with expandable/collapsible nodes. Notice that this example uses a few useful DOM util functions from Firebug framework (FBL namespace).

  • getAncestorByClass(node, className) Returns an ancestor of a node with specified className.
  • hasClass(node, className) Returns true if a given className is present on specified node.
  • removeClass(node, className) Removes a given className from a node
  • setClass(node, className) Adds a given className to a node.

This example is a bit complex, but every aspect of it has been already explained in previous examples.

.treeRow.hasChildren .treeLabel {
    background-image: url(/images/twistyClosed.png);
    background-repeat: no-repeat;
    background-position: 2px 2px;
}

.treeRow.hasChildren.opened .treeLabel {
    background-image: url(/images/twistyOpen.png);
}

.treeRow .treeLabel {
    padding-left: 18px;
    padding-right: 10px;
    white-space: nowrap;
}

.treeRow.hasChildren .treeLabel:hover {
    color: blue;
    cursor: pointer;
    text-decoration: underline;
}
var treeData = {"menu":{"appetizers":[{"name":"some yummy appetizer","prize":{"ammount":8,"currency":"EUR"}},{"name":"a not so yummy soup","prize":{"ammount":5,"currency":"EUR"}}],"main-meals":[{"name":"bunny leg with fries and ketchup","prize":{"ammount":13,"currency":"EUR"}},{"name":"bunny stew","prize":{"ammount":12,"currency":"EUR"}}]},"owners":[{"last-name":"Hunter","first-name":"Bunny"}],"name":"Le lupin","cooks":[{"last-name":"Pits","first-name":"Sweaty"}],"address":{"street":"some french street","zip-code":"123456","city":"some french city","country":"some french country"},"waiters":[{"last-name":"Cheeks","first-name":"Rosy"}]}
var tree = domplate(
{
  tag:
    TABLE({onclick: "$onClick"},
      TBODY(
        FOR("member", "$object|memberIterator",
          TAG("$row", {member: "$member"}))
      )
    ),

  row:
    TR({class: "treeRow", $hasChildren: "$member.hasChildren",
        _repObject: "$member", level: "$member.level"},
      TD({style: "padding-left: $member.indent\\px"},
        DIV({class: "treeLabel"},
            "$member.name")
      ),
      TD(
        DIV("$member.label")
      )
    ),

  loop:
    FOR("member", "$members",
      TAG("$row", {member: "$member"})),

  memberIterator: function(object)
  {
    return this.getMembers(object);
  },

  onClick: function(event)
  {
    if (!isLeftClick(event))
      return;

    var row = getAncestorByClass(event.target, "treeRow");
    var label = getAncestorByClass(event.target, "treeLabel");
    if (label && hasClass(row, "hasChildren"))
      this.toggleRow(row);
  },

  toggleRow: function(row)
  {
    var level = parseInt(row.getAttribute("level"));

    if (hasClass(row, "opened"))
    {
      removeClass(row, "opened");

      var tbody = row.parentNode;
      for (var firstRow = row.nextSibling; firstRow;
           firstRow = row.nextSibling)
      {
        if (parseInt(firstRow.getAttribute("level")) <= level)
          break;
        tbody.removeChild(firstRow);
      }
    }
    else
    {
      setClass(row, "opened");

      var repObject = row.repObject;
      if (repObject) {
        var members = this.getMembers(repObject.value, level+1);
        if (members)
          this.loop.insertRows({members: members}, row);
      }
    }
  },

  getMembers: function(object, level)
  {
    if (!level)
      level = 0;

    var members = [];
    for (var p in object)
      members.push(this.createMember(p, object[p], level));

    return members;
  },

  createMember: function(name, value, level)
  {
    var hasChildren = (typeof(value) == "object");
    return {
      name: name,
      label: hasChildren ? "" : value,
      value: value,
      level: level,
      indent: level*16,
      hasChildren: hasChildren
    };
  }
});

tree.tag.replace({object: treeData}, parentNode, tree);


Rss Commenti

6 Comments

  1. Very nice tutorial! This answered a lot of questions 🙂

    #1 tan
  2. .. by the way, the WordPress list object shows the number of comments even if they are not approved yet.

    #2 tan
  3. @tan: I am using Akismet (WordPress plugin) to check every comment. If it isn't a spam it should be approved automatically. Any ideas what options could be wrong?

    #3 admin
  4. Hi, I am not familiar with either Akismet or WordPress, but it seems like my comments is not published directly

    #4 tan
  5. Maybe it is a cache thing?

    When I go to the frontpage or a category I see the comment count is correct, but in the article page my comment is not showing

    #5 tan
  6. Cool,

    Your demos are so helpful,

    Keep up the good work,

    Thanks for writing, most people don't bother.

    #6 geeks

Sorry, the comment form is closed at this time.