OpenSocial Templates
From OpenSocial
Contents |
Overview
Until now, the standard approach to rendering data into gadgets has involved manipulating a DOM element's innerHTML and/or dynamically creating DOM elements. While these methods for generating UI have become accepted in the developer community, they can be unwieldy, difficult to maintain, and aren't easily reusable.
OpenSocial Templates give you a canonical method for creating data-driven UI in HTML gadgets while separating markup from programming logic. The result is code that is cleaner, more streamlined, reusable, and much easier to maintain. What's more, OpenSocial Templates support looping and conditional display, giving developers the flexibility to create more elaborate UI elements with less code.
A better approach to data-driven UI
The best way to contrast OpenSocial Templates with typical methods for rendering data in gadgets is to see an example. Suppose you are building a music application and have access to the following data structure:
var song = { title: 'Love song #15', url: 'http://allmusic.com/johndoe/greatesthits/lovesong15.mp3', artist: 'John Doe', album: 'Greatest Hits', albumThumbnail: 'http://allmusic.com/johndoe/greatesthits.jpg' }
If you want to render this data into the UI of your gadget or application, you typically have one of two options: 1) build an innerHTML string or 2) dynamically create a DOM node.
Option 1) Build an innerHTML string.
If you decide to set an existing DOM element's innerHTML string, you end up combining markup with programming logic in your code, resulting in something like this:document.getElementById('outputDiv').innerHTML = '<a href="' + song.url + ' "><img src="' + song.albumThumbnail + '"> ' + song.title + ' BY ' + song.artist + ' FROM ALBUM ' + song.album +'</a>';
Option 2) Dynamically create a DOM node.
If you want to write somewhat cleaner code, you can create a DOM element in JavaScript and avoid writing any HTML. However, the resulting code to produce the same UI is much longer and not much easier to maintain:var link = document.createElement('a'); link.href = song.url; document.getElementById('outputDiv').appendChild(link); var img = document.createElement('img'); img.src = song.albumThumbnail; link.appendChild(img); link.appendChild(document.createTextNode(song.title + ' BY ' + song.artist + ' FROM ALBUM ' + song.album));
A better approach: OpenSocial Templates.
Take a look at how you can use the OpenSocial Templates library to create the same UI using a clean, reusable template:
<script type="text/os-template"> <a href="${url}"> <img src="${albumThumbnail}"/> ${title} BY ${artist} FROM ALBUM ${album} </a> </script>
Note that the above code defines an HTML template that looks like regular XHTML with special variable markup. Here is a brief description of how this template works:
- The template is defined inside
<script>tags of typetext/os-template. - Standard HTML UI tags (anchor and image in this case) can be created inside the template.
- The syntax
${}is used to de-reference variables using expressions that are similar to standard JavaScript.
Song list gadget example
Ready to see OpenSocial Templates in action? The example below shows how you can write a simple gadget that fetches the song data from a URL, binds the data to a template, and renders the template in your gadget UI:
<?xml version="1.0" encoding="UTF-8"?> <Module> <ModulePrefs title="Song List"> <Require feature="opensocial-data" /> <Require feature="opensocial-templates"> </Require> </ModulePrefs> <Content type="html"> <![CDATA[ <script type="text/os-data" xmlns:os="http://ns.opensocial.org/2008/markup"> <os:HttpRequest key="song" href="http://mysongserver.com"/> </script> <script type="text/os-template" require="song"> <a href="${song.url}"> <img src="${song.albumThumbnail}"/> ${song.title} BY ${song.artist} FROM ALBUM ${song.album} </a> </script> ]]> </Content> </Module>
In this example, the song data object is stored on a server that's accessible by the URL http://mysongserver.com. The example uses the <os:HttpRequest> tag to fetch the contents of the URL and associate it with a key called song. This key is passed in to the template via the script tag's require attribute.
Looping and Conditionals
The ease of reuse and enhanced functionality of OpenSocial Templates becomes clear with a more complex example. Consider now an array of song data, as follows:
songs : [ { title: 'Love song #15', url: 'http://allmusic.com/johndoe/greatesthits/lovesong15.mp3', artist: 'John Doe', album: 'Greatest Hits', albumThumbnail: 'http://allmusic.com/johndoe/greatesthits.jpg' }, { title: 'Love song #16', url: 'http://allmusic.com/janedoe/greatesthits/lovesong16.mp3', artist: 'Jane Doe', album: 'Best Of', albumThumbnail: 'http://allmusic.com/janedoe/bestof.jpg' }, { title: 'Single #1', url: 'http://allmusic.com/janedoe/greatesthits/single1.mp3', artist: 'Jane Doe', album: 'Greatest Hits', albumThumbnail: 'http://allmusic.com/janedoe/greatesthits.jpg' }, ]
You can make a few slight modifications to the template from the earlier example to list all of the songs in the array. Add an HTML list tag and set the built-in repeat tag attribute to songs to iterate through the array:
<script type="text/os-template"> <ul> <li repeat="${songs}"> <a href="${Cur.url}"> <img src="${Cur.albumThumbnail}"/> ${Cur.title} BY ${Cur.artist} FROM ALBUM ${Cur.album} </a> </li> </ul> </script>
You can further customize your template to display objects conditionally using the attribute if. The slightly modified template below lists only the songs that are from an album titled "Greatest Hits":
<script type="text/os-template"> <ul> <li repeat="${songs}"> <span if="${Cur.album == 'Greatest Hits'}"> <a href="${Cur.url}"> <img src="${Cur.albumThumbnail}"/> ${Cur.title} BY ${Cur.artist} FROM ALBUM ${Cur.album} </a> </span> </li> </ul> </script>
You can find more information about looping, conditionals, variables, and expressions in the OpenSocial Templates Developer's Guide.
Data Pipelining
The OpenSocial Data Pipelining spec describes a declarative syntax for defining the data that you want to process in your gadget. To process data in templates, add <Require feature="opensocial-data" /> to your gadget's ModulePrefs.
Accessing data from external servers
Use <os:HttpRequest> to fetch data that's stored at an external server, as in the example above.
These are some of the fields that you can use with <os:HttpRequest>:
-
@key: identifies the data in the response back -
@href: the URL where the data object is stored -
@params: additional URL parameters -
@method: the HTTP method to use
You can find the complete list of fields to use with <os:HttpRequest>in the Data Pipelining spec.
Accessing data from OpenSocial containers
In addition to accessing data that is stored at an arbitrary URL, you can also request the following types of OpenSocial data: profile information for people, viewer or owner profiles, activities, and container-specific endpoints.
For example, the gadget example below uses the <os:PeopleRequest> tag to access a viewer's friends by setting the attribute userId to @viewer and groupId to @friends. The friends are then rendered in a list using an OpenSocial Template.
<?xml version="1.0" encoding="UTF-8"?> <Module> <ModulePrefs title="Server-side Template"> <Require feature="opensocial-data" /> <Require feature="opensocial-templates"> </Require> </ModulePrefs> <Content type="html"> <![CDATA[ <script xmlns:os="http://ns.opensocial.org/2008/markup" type="text/os-data"> <os:PeopleRequest key="friends" userId="@viewer" groupId="@friends"/> </script> <script type="text/os-template"> <ul> <li repeat="${friends}"> <span id="id${Context.Index}">${Cur.name.givenName}</span> </li> </ul> </script> ]]> </Content> </Module>
You can find the complete list of data request tags and the fields you can use with them in the Data Pipelining spec.
Reference
Refer to these resources for more information about OpenSocial Templates:
