gorevel

Choosing a template from a ViewArg in Revel


Using the Revel framework, is it possible to chose a template based on the value of a ViewArg?

I defined a base controller which provides a method that renders content within views/Layout.html

type Controller struct {
    *revel.Controller
}

func(c *Controller) RenderView(view string, extraViewArgs ...interface{}) revel.Result {
    // ... omitted source
    c.ViewArgs["ContentTemplateName"] = view

    return c.RenderTemplate("layout.html")
}

An example controller implementing this is as follows

type MyController struct {
    Controller
}

func (c MyController) Index() revel.Result {
    bananas := "This is bananas"
    return c.RenderView("App/Bananas.html", bananas)
}

I then try to render "App/Bananas.html" within layout.html

{{set . "title" "Home"}}
{{template "header.html" .}}

<div class="container">
  <div class="row">
    {{template "flash.html" .}}
  </div>
  <!-- Left column of Content -->
  <div class="col-md-9 col-sm-8 col-xs-12">
    {{template .ContentTemplateName .}}
  </div>
  <!-- //Left Column of Content -->

  <!-- Right column of summary -->
  <div class="col-md-3 col-sm-4 hidden-xs">
    <div class="container">
      {{template "sidebar.html" .}}
    </div>
  </div>
  <!-- //Right column of summary -->
</div>

{{template "footer.html" .}}

This outputs the following result

ERROR 2018/08/31 17:46:10 template.go:338: Template compilation error (In layout.html around line 10):
unexpected ".ContentTe"... in template clause
ERROR 2018/08/31 17:46:10 server.go:99: Template Compilation Error (in layout.html:10): unexpected ".ContentTe"... in template clause

Solution

  • Based on a comment by @mh-cbon, it was discovered that its not possible to use a variable as input to the template function.

    As a workaround to this problem to get closer to the desired features, I implemented the following (less than ideal) solution:

    base_content_view.html

    {{template "begin_content.html" . }}
      <!-- content here -->
    {{template "end_content.html" . }}
    

    begin_content.html

    {{template "header.html" . }}
    
    <div class="container">
      <div class="row">
        {{template "flash.html" .}}
      </div>
        <!-- Left column of Content -->
      <div class="col-md-9 col-sm-8 col-xs-12">    
    

    end_content.html

      </div>
      <!-- //Left Column of Content -->
    
      <!-- Right column of summary -->
      <div class="col-md-3 col-sm-4 hidden-xs">
        <div class="container">
          {{template "sidebar.html" .}}
        </div>
      </div>
      <!-- //Right column of summary -->
    
    {{template "footer.html" .}}
    

    base_content_view.html is a static file which is copy pasted as a template when making new views. This design does open other issues however serves as an example workaround for the limitation of the template function.