closure-builder
Version:
Simple Closure, Soy and JavaScript Build system
148 lines (116 loc) • 4.79 kB
Markdown
# Rendering a Template in JS
[TOC]
## How do I render a `Closure Templates` template using JavaScript?
### Generating JavaScript functions from `Closure Templates` files
The first step is to use the `Closure Templates` compiler to compile a `.soy` file
to a corresponding JavaScript file.
See [Compiling Templates](dir.md) for more details.
Your `foo.soy` file generates a `foo.soy.js` file. Each template in `foo.soy`
generates a JavaScript function of the same name in `foo.soy.js`, which you can
call from handwritten JS to render the template. For example, the following
template:
```soy
{namespace soy.examples}
/**
* Says hello to the world.
*/
{template .helloWorld}
Hello world!
{/template}
```
will be compiled to something like
```js
goog.provide('soy.examples.helloWorld');
/**
* @param {Object<string, *>=} opt_data
* @param {Object<string, *>=} opt_ijData
* @return {!goog.soy.data.SanitizedHtml}
*/
soy.examples.helloWorld = function(opt_data, opt_ijData) {
// implementation details here
};
```
The exact signature of the generated JavaScript function is an implementation
detail. Currently, it is:
```js
/*
* @param {Object<string, *>=} opt_data
* @param {Object<string, *>=} opt_ijData
* @param {Object<string, *>=} opt_ijData_deprecated
* @return {!goog.soy.data.SanitizedHtml}
*/
soy.examples.helloWorld = function(opt_data, opt_ijData, opt_ijData_deprecated) {
// ...
}
```
The generated JavaScript function takes optional params representing the
different kinds of data that a `Closure Templates` template can use. It returns a
[SanitizedContent
object]
representing the rendered result.
The exact return type of the generated JavaScript function depends on the
template's [content kind](security#content_kinds). Most templates have a content
kind of `html`, so most generated JavaScript functions return a
[SanitizedHtml]
object, a subclass of SanitizedContent. The other SanitizedContent objects
correspond to the other content kinds: SanitizedCss for `kind="css"`, etc.
Templates of `kind="text"` return a raw JavaScript `string`.
### Calling JavaScript functions from user code
Rendering templates from user code is simply a matter of calling the generated
JavaScript function. For example:
```js
goog.require('soy.examples.helloWorld');
const output = soy.examples.helloWorld();
```
Here, `output` is a SanitizedContent object containing the string `'Hello
world!'`. Note that because the `.helloWorld` template did not declare any
params, it is legal to call the generated JavaScript function without any
arguments. The next section discusses how to pass template data.
### Passing template data {#template-data}
To render a template with data, you can construct a one-off JavaScript object to
pass into a generated template function, or you can reuse an object that already
exists in your code (in which case it can contain keys that are not parameters
to the templates that you're calling). For example:
```soy
{namespace soy.examples}
/**
* Says hello to a person.
*/
{template .helloName}
{@param name: string}
Hello {$name}!
{/template}
```
Example usage:
```js
const output1 = soy.examples.helloName({name: 'Alice'});
const data = {
name: 'Alice',
id: 1,
};
const output2 = soy.examples.helloName(data);
```
Here, both `output1` and `output2` would be SanitizedContent objects with the
content `'Hello Alice!'`. Note that `data` contains an additional key-value
pair. This does not affect the output of the rendered template, as long as the
required template data is present.
The JavaScript implementations of the template data types are:
Template Type | JavaScript Type
------------------------- | -----------------
`null` | `null`
`bool` | `boolean`
`int` | `number`
`float` | `number`
`string` | `string`
`list<T>` | `Array<T>`
`map<K, V>` | `Map`, `jspb.Map`
`legacy_object_map<K, V>` | `Object`
[Maps](../reference/types#map) and [legacy object
maps](../reference/types#legacy_object_map) are distinct types in Soy's type
system, and generate different JS code. Maps must be rendered with JavaScript
`Map` or `jspb.Map` instances; legacy object maps must be rendered with plain
JavaScript `Object` instances. Rendering a template with a `map` parameter using
a plain JavaScript `Object`, or vice versa, will cause a runtime error. This
means that when you change a template parameter from `legacy_object_map` to
`map`, you must also change the JavaScript value used to render it from a plain
`Object` to a `Map`.