WARNING: This page is a guide for 1.x series. See here instead to learn about the latest

View Templates


Scalate


Skinny framework basically follows Scalatra’s Scalate Support, but Skinny has an additional convention.

Scalate Logo

Template paths should be of the form {path}.{format}.{extension}. Expected {format} are html, json, js and xml.

For instance, assuming your controller code looks like this:

class MembersController extends SkinnyController {
  def index = {
    set("members", Member.findAll())
    render("/members/index")
  }
}

The render method expects that src/main/webapp/WEB-INF/views/members/index.html.ssp exists.

<%@val s: skinny.Skinny %>
<%@val members: Seq[model.Member] %>
<h3>Members</h3>
<hr/>
<table class="table table-bordered">
<thead>
  <tr>
    <th>ID</th>
    <th>Name</th>
    <th></th>
  </tr>
</thead>
<tbody>
  #for (member <- members)
  <tr>
    <td>${member.id}</td>
    <td>${member.name}</td>
    <td>
      <!-- Using Scalatra reverse routes is recommended -->
      <a href="${s.url(MembersController.editUrl, "id" -> member.id)}" 
         class="btn btn-info">Edit</a>
      <a data-method="delete" data-confirm="Are you sure?" 
         href="${s.url(MembersController.deleteUrl, "id" -> member.id)}"
         class="btn btn-danger">Delete</a>

      <!-- Primitive HTML coding is also possible -->
      <a href="/members/${member.id}/edit" class="btn btn-info">Edit</a>
      <a data-method="delete" data-confirm="Are you sure?"
         href="/members/${member.id}" class="btn btn-danger">Delete</a>
    </td>
  </tr>
  #end
</tbody>
</table>

Scalate supports many template engines.

http://scalate.github.io/scalate/

For example, if you want to write your template using Jade, save it as src/main/webapp/WEB-INF/views/members/index.html.jade instead.

Scaffolding will be the easiest way to understand. Try it now!

./skinny g scaffold members member name:String activated:Boolean birthday:Option[LocalDate]
./skinny g scaffold:scaml companies company name:String 
./skinny g scaffold:jade  countries country name:String code:Int

./skinny db:migrate
./skinny run

./skinny run evaluates Scalate templates on runtime and that makes your Skinny app developmeent so interactive.

When you edit a template file a little, just reload the page without waiting for Scala code compilation and Jetty restart due to Scala compilation detection.

However, in some cases, error messages may be difficult to investigate the reason or page response may be slow when it’s the first request to the page. If you’d like to use Scalate precompilation in development, just append -precompile option as follows.

./skinny run -precompile

For instance, if you use Jade instead, the above code will look like this. Scaml is very similar.

-@val s: skinny.Skinny
-@val members: Seq[model.Member] 
h3 Members
hr
table(class="table table-bordered")
  thead
    tr
      th ID
      th Name
      th
  tbody
  -for (member <- members)
    tr
      td #{member.id}
      td #{member.name}
      td
        a(href={s.url(MembersController.editUrl, "id" -> member.id)} class="btn btn-info") Edit
        a(data-method="delete" data-confirm="Are you sure?" href={s.url(MembersController.deleteUrl, "id" -> member.id)} class="btn btn-danger") Delete
        a(href={s"/members/${member.id}/edit"} class="btn btn-info") Edit
        a(data-method="delete" data-confirm="Are you sure?" href={s"/members/${member.id}"} class="btn btn-danger") Delete

Layouts


To avoid unnecessary repetition and ease maintenance, you may want to extract common parts of your Scalate templates into ‘layouts’. See the Scalate documentation for more details.

If you do not specify which layout to use, Skinny will look for a ‘default’ layout at WEB-INF/layouts/default.{extension}. (Note that the layout does not necessarily have to use the same template language as the template.)

If you want to use a custom layout for a particular action, use the layout method in your controller:

class MyController extends SkinnyController {

  def foo = {
    layout("custom.ssp")
    render("foo") // Renders WEB-INF/views/foo.html.ssp using layout WEB-INF/layouts/custom.ssp
  }
}

FreeMarker


If you prefer the FreeMarker template engine, you can easily use it with Skinny framework.

http://freemarker.org/

First, add skinny-freemarker to your library-dependencies.

libraryDependencies += "org.skinny-framework" %% "skinny-freemarker" % skinnyVersion

Mixin FreeMarkerTemplateEngineFeature to your controllers.

import skinny.controller.feature.FreeMarkerTemplateEngineFeature

class MembersController extends SkinnyController
  with FreeMarkerTemplateEngineFeature {

  def index = {
    set("members", Member.findAll())
    render("/members/index")
  }
}

And then, use src/main/webapp/WEB-INF/views/members/index.html.ftl instead.


Thymeleaf


If you prefer the Thymeleaf template engine, you can easily use it with Skinny framework.

http://www.thymeleaf.org/

First, add skinny-thymeleaf to your library-dependencies.

libraryDependencies += "org.skinny-framework" %% "skinny-thymeleaf" % skinnyVersion

Mixin ThymeleafTemplateEngineFeature to your controllers.

import skinny.controller.feature.ThymeleafTemplateEngineFeature

class MembersController extends SkinnyController
  with ThymeleafTemplateEngineFeature {

  def index = {
    set("members", Member.findAll())
    render("/members/index")
  }
}

And then, use src/main/webapp/WEB-INF/views/members/index.html instead.


Velocity


If you prefer the Velocity template engine, you can easily use it with Skinny framework.

http://velocity.apache.org/

First, add skinny-velocity to your library-dependencies.

libraryDependencies += "org.skinny-framework" %% "skinny-velocity" % skinnyVersion

Mixin VelocityTemplateEngineFeature to your controllers.

import skinny.controller.feature.VelocityTemplateEngineFeature

class MembersController extends SkinnyController
  with VelocityTemplateEngineFeature {

  def index = {
    set("members", Member.findAll())
    render("/members/index")
  }
}

And then, use src/main/webapp/WEB-INF/views/members/index.html.vm instead.

If you find a typo or mistake in this page, please report or fix it. How?