Templates

Note

This help should be accurate and comprehensive. If you see anything missing or that needs to be fixed, see How to Contribute or let us know in the Juice Slack #documentation channel.

Templates turn data into html. Juicebox has many templates built-in.

Juicebox uses Juice’s open-source Dunderscore Templates library. Dunderscore combines the flexibility of using plain javascript Underscore templates (see http://underscorejs.org/#template) with filters inspired by Vega Datalib (https://github.com/vega/datalib/wiki/Formatting#dl_template).

Two types of templates

Templates have global access to all data in any slice by referring to other slugs. Some templates are bound to an data object called datum.

Built-in template functions

All the built-in functions are called by referencing the slug for the slice you’re interested in followed by the function name.

<%= <slug>.<functionName>() %>

selection

Provides the list of selected items in the slice with slug <slug>. Each item will have an id, a label, and a group_by_type.

optionchooser.selection()
// Returns: [{id: 'expenditures', 'label': 'Expenditures', 'group_by_type': 'sel_type'}]

selectionDisplay

Provides a string of the selected items of the slice with slug <slug> for display.

  • If there are no selections, displays “All <dimension>s”
  • If there is 1 selection, displays “<label_of_the_selected_item>”
  • If there are > 1 selections, displays “<num_of_selections> <dimension>s”

This is a shortcut way of referring to the following template.

//ranked_list.selectionDisplay() is the same as

<% if (ranked_list.selection().length == 1) { %>
    <%= ranked_list.selection()[0].label %>
<% } else if (ranked_list.selection().length > 1) { %>
    <%= ranked_list.selection().length ranked_list.metadata(ranked_list.selectionType(), 'plural') %>
<% } else { %>
    All <%=ranked_list.metadata(ranked_list.selectionType(), 'plural')%>
<% } %>

This method also accepts a “dimension” parameter that limits the display string to only the selection of items whose group_by_type == “dimension”. This is helpful for slices like the Option Chooser that can show multiple groups of options, each with their own group_by_type.

// option_chooser.selectionDisplay('attempt_type') is the same as

<%
  var selection = option_chooser.selection(),
      type      = 'attempt_type';

  selection = selection.filter(function(d) {
    return d.group_by_type == type;
  });
%>

<% if (selection.length == 1) { %>
    <%= selection[0].label %>
<% } else if (selection.length > 1) { %>
    <%= selection.length option_chooser.metadata(type, 'plural') %>
<% } else { %>
    All <%= option_chooser.metadata(type, 'plural')%>
<% } %>

selectionListDisplay

Provides a comma separated list of the selected items of the slice with slug <slug> for display.

  • If there are no selections, displays “All <dimension>s”
  • If there is 1 selection, displays “<label_of_the_selected_item>”
  • If there are > 1 selections, displays “<label_of_selection_1>, <label_of_selection_2>”

This is a shortcut way of referring to the following template.

//ranked_list.selectionListDisplay() is the same as

<% if (ranked_list.selection().length == 1) { %>
    <%= ranked_list.selection()[0].label %>
<% } else if (ranked_list.selection().length > 1) { %>
    <%= ranked_list.selection() | toSentenceSerial %>
<% } else { %>
    All <%=ranked_list.metadata(ranked_list.selectionType(),'plural')%>
<% } %>

selectionCount

Provides the number of selected items of the slice with slug <slug>.

ranked_list.selectionCount()
// Is same as: ranked_list.selection().length

selectionType

Provides the group_by_type of the current data set.

ranked_list.selectionType()

selectionId

Provides the id of the first selected item.

ranked_list.selectionId()

data (templates)

Provides the data items in the current data set in the same format as <slug>.selection().

ranked_list.data()

dataCount

Provides the number of data items in the current data set.

ranked_list.dataCount()
// Is the same as: ranked_list.data().length

dataCountDisplay(threshold)

Provides a formatted string of the number of data items in the response of the slug with slug <slug> for display. If given a threshold, will short format the number if the number exceeds the threshold.

details_table.dataCountDisplay()
details_table.dataCountDisplay(1000)

dataCountWithDimensionDisplay(threshold)

Provides a formatted string of the number of data items in the response of the slug with slug <slug> for display. If given a threshold, will short format the number if the number exceeds the threshold. The number string is suffixed with the group_by_type of the current data set.

details_table.dataCountWithDimensionDisplay()
details_table.dataCountWithDimensionDisplay(1000)
// is the same as
<%
  var count = details_table.dataCount();
  var suffix = '';
  if (count == 1) {
    suffix = details_table.metadata(details_table.selectionType(), 'singular');
  }
  else {
    suffix = details_table.metadata(details_table.selectionType(), 'plural');
  }
  var s = details_table.dataCountDisplay() + ' ' + suffix;
  s = s.trim();
%>
Review Overall Score for your <%= s|emphasis %>

metadata(id, attribute)

Accesses the metadata of a particular slug.

icon:<font-awesome-icon>

Displays a font awesome icon. See http://fontawesome.io/icons/

Note

This is coming soon.

Filters

Filters can be applied to any string or value and will modify that value. Dunderscore templates support all filters defined here (http://gabceb.github.io/underscore.string.site/).

|emphasis

Surrounds text with <strong> and </strong> tags.

|noemphasis

Removes emphasized text. All the built-in display{*} functions are automatically emphasized. You can turn this off with |noemphasis.

For instance,

There are <%= ranked_list.selectionDisplay()|noemphasis %> users.

|prefix:s

Prefixes text with the string s

For instance,

There are <%= ranked_list.dataCount()|prefix:'$' %> users.
// "There are $1000 users"

|suffix:s

Suffixes text with the string s

|format:formatSpecifier

Formats a number using formatSpecifier.

|capitalize

Capitalizes the first letter of a string.

|truncate:<number of characters>

Truncates a string to a certain number of characters, adding an ellipsis at the end.

|prune:<number of characters>

Truncates a string but doesn’t chop words in half.

|toSentence

Joins an array into a human readable sentence.

<%= ranked_list.selection()|toSentence %>
"a, b and c"

About emphasis

Dunderscore will emphasize template results using the following rules.

  • Every interpolate that displays a string will have an automatic emphasis modifier applied to it which runs last. This modifier wraps the string in a strong tag like <strong>CONTENT</strong>.
  • If a modifier value|noemphasis is present, the emphasis modifier will not be applied.
  • If emphasis and noemphasis are both used (regardless of in which order they appear), no emphasis will show up. For instance, if a template was <%= datum.value|emphasis|noemphasis|emphasis %> there will be no emphasis on the output.

Ways of formatting numbers in templates

If we had

// Datum is the following
{ "value": 0.1234,
  "salesValue", 1234.568,
  "valueProp": "salesValue",
  "formatField": "sales" }

// Metadata is the following
{ "foo": { "format": "0.2f" },
  "sales": { "format": "$0.2f" },
  "value": { "format": "0.2%" },
  }
:<%= datum.value|format:'0%' %> of viewers: Take the value property of

datum and format it as percentage with no decimal points.

12% of viewers
<%= datum.format('value', '0%') %> of viewers:
 

Take the value property of datum and format as with no decimal points. This is exactly the same as the previous template.

The result would be: 12% of viewers

<%= datum.format('value') %> of viewers:
 

Take the value property of datum and format it using the metadata.value .format (which is “0.2%” in this example.

The result would be: 12.34% of viewers

<%= datum.format('value', null, 'foo') %> of viewers:
 

Take the value property of datum (0.1234) and format it using the metadata.foo.format (“0.2f”). The null can be anything falsey.

The result would be: 0.12 of viewers

<%= datum.format('value', null, datum.formatField) %> of viewers:
 

Take the value property of datum (0.1234) and format it using the metadata[datum.formatField].format (“$0.2f”)

The result would be: $0.12 of viewers

<%= datum.format(datum.valueProp) %> of viewers:
 

Take the valueProp string of the datum and get that property FROM the datum and format it using metadata[datum.valueProp].format. So if datum .valueProp is “foo”, this is the same as <%= datum.format(‘foo’) %>.

<%= datum.value|format %> of viewers:
 

Note

DOES NOT WORK, but could someday :-) Would be same as <%= datum.format('value') %> of viewers

:<%= datum.value|format:datum.formatString %> of viewers:

Danger

This doesn’t work :-|

Examples.

Display the current selection of a slice.

<%= option_chooser2.selectionDisplay() %> breakdown

// Outputs: <strong>Total Sales</strong> breakdown

// In v2 you did: <strong>{{=selection('option_chooser2')}}</strong> breakdown

Display the current selection of a slice with different output for different scenarios.

<% if (ranked_list.selectionCount() == 0) { %>
  Student details
<% } else { %>
  Students who missed questions in <%= ranked_list.selectionDisplay() %>
<% } %>

// In v2 you did:
{{= selection('ranked-list',
              {
                placeholders:{
                              'count:0':'Student details',
                              '*':'Students who missed questions in <strong>{=selection("ranked-list")}</strong>'
                              }
              })
}}
// Another example
<% if (key_metrics.selectionCount() && key_metrics.selectionId() ==  'expenditures_amount') { %>
  Expenditure Detail
<% } else { %>
  Lead Investigator Detail
<% } %>

// In v2 you did:
{{= selectionWithPlaceholders('key-metrics', {'expenditures_amount': 'Expenditure Detail', '*': 'Lead Investigator Detail'}) }}
// Another example
Explore <%= keymetrics_hierarchy.selectionDisplay('metric') %> results for your learners.

// In v2 you did:
Explore <strong>{{= selection('keymetrics-hierarchy', {'dimension': 'metric'}) }}</strong> results for your learners.

Take the number of selections in the details table and format it as a comma delimited number.

<%= details_table.selectionCount()|format:",.0f" %>

// In v2 you did:
{{= selectionsCount('details-table') }}

Get the type of selection chosen in the ranked list slice and format it using the metadata plural value for that selection type.

Pick <%= rankedlist.metadata(rankedlist.selectionType(), 'plural')|emphasis %>
that interest you, or choose another grouping.

// In v2 you did:
Pick <strong>{{=dimension()}}</strong> that interest you, or choose another grouping.

Show a nicely formatted list of the selected items in the table slice.

Review <%= keymetrics_hierarchy.selectionDisplay() %> for your <%= details_table.dataCountWithDimensionDisplay() %>.

// In v2 you did:
Review <strong>{{= selection('keymetrics-hierarchy', {'dimension': 'metric'}) }}</strong> for your
<strong>{{= itemsCount('self') }}</strong>.
// Another example
We found <i class='icon icon-user'></i> <%= details_table.dataCountWithDimensionDisplay(1000) %>

// In v2 you did:
We found <i class='icon icon-user'></i> {{=itemsCountWithThreshold('self', 1000) }}

An option chooser item template.

<div data-id="<%= datum.id %>" data-label="<%= datum.label %>" class="group-container__item">
    <div class="group-container__item__value">
        <%= datum.format('value','0%') %> of viewers
    </div>
    <div class="group-container__item__label">
        consumed <%= datum.season %> <%= datum.label %>
    </div>
    <div class="group-container__item__avg">
        Network Average is <%= datum.format('network_average',',.0%') %>
    </div>
</div>

// In v2 you did:
<div data-id="{{=id}}" data-label="{{=label}}" class="group-container__item">
  <div class="group-container__item__value">{{=format('value','0%')}} of viewers</div>
  <div class="group-container__item__label">consumed {{=season}} {{=label}}</div>
  <div class="group-container__item__avg">Network Average is {{=format('network_average','0%')}}</div>
</div>