Discuss or ask a question
Templating is way to generate dynamic pages. In tales Html stays html and you use a jquery like api to put dynamic data into it
Html templating
A html page that is displayed will at minimum have two file associate with it
  • a html template file
  • a fantom file that "puts" dynamic data into it
Let's start with an example, create a new tales app. The home page that you see is generated using
  • template/Index.html
  • fan/Index.fan
Delete everything in Index.html and replace it with:
<div talesId="name">Test</div> 
Open Index.fan and add this code in main() method:
html := Html("template/Index.html")
html.tag("text").text("Jhon")
response.writeTag(html)
Refresh the browser. The generated html will look like this
<div>Jhon</div>
Things to note:
  1. The only div in html, had a talesId = "name"
  2. The general syntax of markup in fan is
    html.tag("talesid").text(str)
  3. The output strips off the talesId but replaces the text of the tag with whatever you supplied in the fantom markup
Let's look at a deeper example
Imagine you wanted to display a text that greets the user. You could write something like
username := "Kaushik"
html.tag("talesid").text("Hello, welcome <b>$username</b>")
A better way to do it would be to move all markups to html. You can write something like this:
<div>Hello, welcome <b talesId="name">Something</b></div>
and in markup
username := "kaushik"
html.tag("name").text(username)
Changing other attributes
You can manipulate other attributes using the ".attr()" method
html:
<div talesId="name">Something</div>
fan:
html.tag("name").text("Kaushik").attr("style", "color:red")
will result in html
<div style="color:red">Kaushik</div> 
Another example:
Html:
<a href="#" talesId="myLink">Click here</a>
Fan:
html.tag("myLink").attr("href","/user/id/1")
Will result in:
<a href="/user/id/1">Click here<a>
Adding and removing classes and styles
The "Tag" class provides convenient shortcuts for adding and removing classes
html:
<div talesId="name">Something</div>
fan:
html.tag("name").addClass("active").addCss("color", "red")
will result in html:
<div style="color:red" class="active">Kaushik</div> 
Nested and duplicate markups
talesids need not be unique.
Html:
<div talesId = "name" style="color:red"></div>
<div talesId = "name" style="color:blue"></div>
Fan:
html.tag("name").text("Jhon")
Will result in html:
<div talesId = "name" style="color:red">Jhon</div>
<div talesId = "name" style="color:blue">Jhon</div>
talesIds can be nested. For eg.
<div talesId="two"></div>
<div talesId = "one"> 
  <div talesId = "two" ></div>
</div>
A fantom code like this
html.tag("two").text("Hello")
Will affect nested and non-nested tags like this
<div>Hello</div>
<div> 
  <div>Hello</div>
</div>
However you can choose to affect only nested tags like this
oneTag := html.tag("one")
oneTag.tag("two").text("Hello")
The output will be
<div>/div>
<div talesId = "one"> 
<div>Hello</div>
</div>
Repeaters
You might want to repeat a tag multiple times
Html:
 <div talesId="numbers"></div> 
Fan:
vals := ["One", "Two", "Three"]
html.tag("numbers").repeating
vals.each{
  tag := html.tag("numbers").addRow
  tag.text("$it")
}
gives an output:
<div>One</div>
<div>Two</div>
<div>Three</div>
Repeating-tags themselves can have nested talesIds:
<ul>
  <li talesId="number">
    <span talesId="val"></span>
  </li>
</ul>
Fan:
vals := ["One", "Two", "Three"]
html.tag("numbers").repeating
vals.each{
  numberRow := html.tag("numbers").addRow
  numberRow.tag("val").text("$it")
}
gives an output:
<ul>
  <li>
       <span>One</span>
  </li>
  <li>
       <span>Two</span>
  </li>
  <li>
       <span>Three</span>
  </li>
</ul>
Instead of calling ".repeating()" method you can call ".repeat(num)" if you know the number of times of repetition ahead of time. For eg.
<span talesId="name">Test</span>
and Fan:
tags := html.tag("name").repeat(10)
tags.each|Tag tag, Int index|{
	tag.text("$index")
}
will result in html
<span>1</span><span>2</span><span>3</span>
Panels and Layouts
There is no separate concept of panels and layouts but you can arbitrarily nest tags with file names for eg., Consider this panel
<div>Hello, I am a panel</div>
and another page
<div> I am a parent panel <div talesId="child"></div></div>
You can include the panel in page like this
page := Html("template/page.html")
panel := Html("template/panel.html")
page.tag("child", panel)
response.writeTag(page)
Apply method and "Cut and Send"
On any Html tag you can call the apply method to get the html
for eg., Html:
<span talesId="name"></span>
and fan:
html := Html("template/page.html")	
html.tag("name").text("Jhon")
Str result := html.apply
echo(result)
will print <span >Jhon</span> to the output.
You can only ask for portions of html instead of complete html. For eg.
Html:
<span>Title</span>
Some other html
<span talesId="age"></span>						
and fan
ageTag := Html("template/page.html").cutAt("age")
ageTag.text("20")
result := ageTag.apply
echo(result)
will print <span >20</span> to the output (only html corresponding to tag with talesId="age").