Obviel Template is a template language for Obviel. Obviel Template is
deliberately a very minimal template language. The idea is that more
complicated logic should be kept in JavaScript code, not templates,
because it is much clearer to express it in JavaScript. You can do
this by preprocessing the object that goes into the template, or by
using data-func in the template.

Obviel Template is different from many template languages you might
have encountered in that it is element-based and HTML aware, not
text-based. Templates must be valid HTML fragments. If you try to
construct a template with elements in places where they are not valid
HTML, you will find that the browser will not produce that HTML. The
advantage of being element-based is that the template language can
directly operate on the DOM. You can for instance directly bind event
handlers in the template language.

Obviel Template integrates with Obviel in an important way: sub-views
can be rendered directly from the template. This allows these views to
work in the standard Obviel way. They can for instance respond to
events on the objects that they are representing, and rerender
themselves. This is another benefit of Obviel Template being
element-based.

Another powerful feature of Obviel Template is that it supports i18n
markers directly in the template for the purpose of
internationalization (i18n) of template texts. This is based on
standard gettext, and supports pluralization. This way automatic
extraction tools can be used to maintain translations of strings in
the template. This feature exists in some server-side template
languages (such as Zope Page Templates), but this is not commonly
supported by client-side template languages.

In Obviel Template, special variables start with @, and @.
means “the current object”. This can be useful for debugging
templates: you can see what the current object is somewhere. The
current object will be serialized to JSON into the rendered template.

So to address something.persons in a loop, you use
something_persons, with the . replaced by _.

To support various user interface you want to add a class into the DOM
depending on a some @each value, such as even or
odd. While you can do this with data-attr (which we’ll see
later), we recommend you use data-func for this (which we’ll also
see later), as your code will generally be clearer.

This works. But we could also arrange our code so that we have a view
for the person iface and use that instead. The advantage of that
is that we could reuse this view in other places, and in addition we
can use Obviel view features, such as binding its methods to DOM
events (which we’ll see later). Let’s consider a view:

obviel.view({iface:'person',obvt:'<a href="{url}">{name}</a>'});

This is a view for the iface person. We use the Obviel Template
(indicated by obvt) to render the view.

Another advantage of using data-view in this case is that you have
made the outer template more generic. If the object indicated by the
name who has another iface, the template will still work
unchanged. For example, here is a data structure where who is a
robot:

{greeting:"Greetings",who:{iface:'robot',designation:"OVL-R 4711",}}

and this is a view for the iface robot:

obviel.view({iface:'robot',obvt:'{designation}'});

and here is our outer template again, unchanged:

<p>{greeting} <spandata-view="who"></span></p>

when we render the data now, we get this:

<p>Greetings <span>OVL-R 4711</span></p>

in other words, if you add data-view to an element el to
render object who, Obviel Template will do the equivalent of this:

$(el).render(who);

Sometimes you have multiple views for an iface, distinguished by
name. You can indicate the name used by data-view with a |
character. Here’s another view for person with the name extended:

obviel.view({iface:'person',name:'extended',obvt:'The person has the name <a href="{url}">{name}</a>'});

and here is how you refer to this extended view:

<p>{greeting} <spandata-view="who|extended"></span></p>

By default, data-view looks up a view named default – the default
view name for Obviel. If you want to change the way templates look up
views to use another view globally you can do so in JavaScript:

obviel.template.setDefaultViewName('summary');

From now on if you don’t specify the view name explicitly, Obviel will
look up views by the name of summary by default. If you decide to
do this, you would want to do this once per web page before template
rendering takes place, for instance when the page has just been
loaded. Note that this does not alter the default view name of
Obviel itself when you use el.render(obj); this will remain
default.

data-view can also point to a variable that is a string, not an
object. In this case the variable is treated as a URL, and this is
loaded as a JSON object. The view is then rendered for that object.

data-view must point to an object or a string. It cannot point to an
array or other value.

Obviel Template has element-based directives (data-if,
data-each, etc). But sometimes you just want to conditionally or
repeatedly include a piece of text, not an element. You can do this by
using a special data-unwrap element. During template rendering all
elements marked by data-unwrap disappear.

In the case where you need to use data-attr, always consider
using data-func instead. Your code will often be a lot more
clear and easier to write with a small custom method on the view
that adds attributes using jQuery than it is using data-attr.

data-attr with special HTML elements

In HTML, the following elements are void, meaning they may not
contain any element or text content: area, base, br,
col, command, embed, hr, img, input,
keygen, link, meta, param, source, track,
wbr. In addition, there are two elements that may only contain
text content (title and textarea). Other elements have other
restrictions; they may for instance only contain text content
(textarea is an example), or only sub-elements of a certain type
(ul is an example).

For void elements you cannot put an element with data-attr
inside of such an element to generate an attribute on the outer void
elements. For an element with a text-only restriction or content
restritions you may also have trouble. What then if you want to
generate attributes dynamically for a void element such as input?
This, after all, is then illegal:

This is all rather cumbersome however, and we recommend you use
data-func in these situations instead.

Normally you’d generate a dynamic attribute like this:

<ahref="{url}">{title}</a>

but sometimes this isn’t good enough: in particular, we sometimes want
to be able to generate attributes that are only there if some
condition is true. Obviel Template has a special data-attr
directive that lets you do this. The equivalent of the above example
using data-attr looks like this:

<a><spandata-attr="href"data-value="{url}"/>{title}</a>

What will happen when this template is rendered is the same as in the
first example:

<ahref="/some/url">Some Title</a>

data-attr will always apply to the element it is directly
contained in. Note that the element that has the data-attr on it
itself is never inserted in the result.

This construct is helpful because you can use data-if for conditional
attributes now:

<a><spandata-if="flag"data-attr="href"data-value="{url}"/>{title}</a>

Now, the href attribute will appear only if flag is true.

In combination with data-each this can be used to dynamically
generate multiple attributes from data:

If you generate the same attribute multiple times the content is added
to the existing attribute, with a space character for a separator.
This is for instance useful when you want to add multiple classes
dynamically to an element and have some show up only if a condition is
true. This:

In general the rule is that any operations that alter the amount of
child nodes of the element (or sub-elements) in the DOM are
forbidden, though there are some exceptions. We’ll go into some
(non-exhaustive) detail here.

Safe:

add attribute (i.e. attr).

remove attribute (i.e. removeAttr).

change attribute (ie. attr or addClass).

append a new child element at the end of the current element
(using .append).

change text using .text as long as the element does not
contain any sub-elements but only text content. If it does contain
sub-elements, text nodes can still be manipulated as long as they
are not removed.

replace a child element with another, as long as that other has
exactly the same structure (text and sub-elements recursively).

Unsafe operatons:

move a child element (i.e. after, before).

remove a child element (i.e. remove, empty).

remove text nodes.

replace a child element with another that does not have the
same structure (text and sub-elements recursively).

In many cases it is more convenient to use JavaScript and jQuery to
manipulate the DOM directly than it would be to use Obviel Template
constructions such as data-attr. Obviel Template offers a special
directive called data-func that lets you plug custom functions
into the template rendering process directly.

To see what data-func does, let’s consider a simple case first. Let’s
imagine these two individuals:

Especially for more complicated logic, this is often a lot more easy
to understand.

The method called by data-func gets an optional second argument,
variable. This is a function you can use to get to variables in
the same scope as the template does where data-func was
defined. Let’s rewrite the view to use variable:

everythird cannot be expressed using Obviel Template alone, but is
easy to express using a custom fuction.

So using data-func you can supplement Obviel Template with
functionality particular to your views or application. This is useful
for particular functionality your view needs, or for general
functionality your whole application needs.

There are some restrictions on data-func. You should only use
data-func to change the element, for instance by manipulating
its attributes, not to add or remove child elements (or
text-nodes). Most DOM manipulations by adding, moving or removing
elements or text modes are unsafe: it can break Obviel Template in
unexpected ways, as it relies on the order of child nodes to stay the
same. But if you want to insert a whole bunch of elements you should
consider using data-view instead.

Since Obviel templates use HTML and the HTML compiler internally,
Obviel templates should be valid HTML fragments.

In valid HTML, an id attribute should be unique. If the id
attribute is hardcoded there is no problem; you can just use them:

<divid="foo"></div>

But variables in ids are not allowed, because it would be too easy to
have a HTML fragment with the same id (such as {myId}) in multiple
id attributes. So this is illegal:

<divid="{myId}"></div>

If you try this, you’ll get an compilation error.

To generate an id dynamically, you can instead use the data-id
directive:

<divdata-id="{myId}"></div>

This works just like any other attribute, so you can put things before
and after the variable:

<divdata-id="prefix{something}postfix"></div>

This will generate HTML with proper id attributes.

A similar story applies to the src attribute. Let’s consider the
img element. When the template is being parsed, the image referred
to by src is loaded by the browser immediately. So this in your
template would be okay:

<imgsrc="myimage.png"/>

But this is illegal:

<imgsrc="{myImage}"/>

because we wouldn’t want the browser to look for a URL {myImage}
literally. Obviel Template prevents this by giving you a compilation
error when you try this.

Obviel Template offers the ability to write a template that can be
shown in other languages as well: you can internationalize a
template. Here we will discuss the basics of marking up a template so
it can be translated, but much more detail is in a separate
document about template i18n.

If we have a template like this:

<pdata-trans="">Hello world!</p>

we can also show this template in another language, such as Dutch, if
the appropriate translation is available:

<p>Hallo wereld!</p>

data-trans is used to mark up those parts of the template that
should be translatable, such as attributes and texts.

A translatable text can contain variables as well:

<pdata-trans="">Hello {who}!</p>

The data-trans attribute without content is used to mark the
textual content of a tag for translation. If you want to mark an
attribute as translatable you can do it like this:

<divdata-trans="title"title="Hello"/>

You can also mark multiple attributes:

<divdata-trans="title other"title="Hello"other="Something"/>

You can indicate attributes and textual element content with the
special name .:

This means that if the value a is present and true, the p
element will be included in the rendered template (at all). After
this, for each of the entries in b (so b scope, iteratively),
we render the object d in the c scope with a view.

This order holds no matter in what order you define the attributes.

data-trans is at the same level as data-view. It’s not allowed
on an element with data-view.

data-attr and data-func are executed last for an element, and
finally elements are transformed using data-el or data-unwrap.

The HTML CDATA section support in browsers is so inconsistent we
didn’t think it was worth spending time supporting this in templates,
given its limited utility. Obviel Template therefore has undefined
behavior in the presence of CDATA sections in your template: we
recommend you don’t use them. If you want to insert extended sequences
of text in an element you can already do so with a simple variable.