Looping Content

When you’re working with large quantities of user social data, one question naturally arises in the context of OpenSocial templating: how do you handle repeating content, such as a list of friends or any measure of activity data? We certainly won’t be creating a markup definition for each repeating node in the template, will we? The short answer is no.

Content looping in OpenSocial allows a developer to define a block of markup to be used to render a series of repeating elements, without having to resort to handling each repeating node as a separate instance of markup. There are a few ways to define a loop structure within an OpenSocial template specification, which we’ll go over next.

Method 1: Escaped values

The first method is to build a loop structure that outputs the value of a piece of data as an escaped string, much like we saw with conditional statements. Let’s say that we have a customized subset of activity data that is returned to us through a data pipe request:

activities: [
   {
      title: "Jonathan just added a new comment on Twitter",
      body: "See what Jonathan is saying by adding him to Twitter",
      url: "http://www.twitter.com/jcleblanc"
   },
   {
      title: "Michael updated his profile",
      body: "See more about what Michael is doing",
      url: "http://www.container.com/profiles/michael"
   },
   {
      title: "Diane just posted a comment on your wall",
      body: "Reply to Diane's message",
      url: "http://www.container.com/messages"
   }
];

This content structure has several repeating nodes within the object that we can use to build out a complimentary repeating block within an OpenSocial template:

<script type="text/os-template">
   <ul>
      <li repeat="${activities}">
         <a href="${Cur.url}">
            ${Cur.title}
         </a><br />
         ${Cur.body}
      </li>
   </ul>
</script>

We wrap our template content in our script block with the specialized type definition to start out the template declaration. The markup within the script block first defines an unordered list to display the activities. Instead of defining a list item for each element, we simply define a single <li> that contains the repeat declaration:

<li repeat="${activities}">

Here we’ve stated that this element and its content should be repeated based on the objects contained within activities, which we defined earlier. Within the repeated element, we can easily refer to the current object being exposed in the loop by using a provided reference variable:

${Cur.title}

${Cur} allows us to refer to the current object in the loop in question. In this way, we can create an entire markup construct with a smaller code base than we would by defining straight markup. Given the preceding loop, the application would render the complete markup structure for all repeated objects that we iterated over:

<ul>
   <li>
      <a href="http://www.twitter.com/jcleblanc">
         Jonathan just added a new comment on Twitter
      </a><br />
      See what Jonathan is saying by adding him to Twitter
   </li>
   <li>
      <a href="http://www.container.com/profiles/michael">
         Michael updated his profile
      </a><br />
      See more about what Michael is doing
   </li>
   <li>
      <a href="http://www.container.com/messages">
         Diane just posted a comment on your wall
      </a><br />
      Reply to Diane's message
   </li>
</ul>

Method 2: Nonescaped values

The alternate method for looping within an OpenSocial template is to use the os:Repeat tag. This will instruct the template to render any code within the data objects being displayed as actual markup—not just the string representations of the markup.

The looping structure is essentially the same as the previous example, but instead of applying a repeat attribute to the block of markup to be repeated, we wrap the entire block in the os:Repeat tag. If we modify our previous example, the repeat tag would look like:

<script type="text/os-template">
   <ul>
      <os:Repeat expression="${activities}">
         <li>
            <a href="${Cur.url}">
               ${Cur.title}
            </a><br />
            ${Cur.body}
         </li>
      </os:Repeat>
   </ul>
</script>

This produces the same results as the previous example. In addition to the standard repeat syntax, you can use the var attribute to assign a different variable name to the repeater:

<os:Repeat expression="${activities}" var="myActivities">
   <li>
      <a href="${myActivities.url}">
         ${myActivities.title}
      </a><br />
      ${myActivities.body}
   </li>
</os:Repeat>

Working with nested repeaters

When working with repeaters, you may need to nest multiple loop structures together to get the desired visual results. But nesting repeaters has its own challenges when it comes to accessing the current result object in the loop using ${Cur}.

Variable naming is an excellent method for obtaining the desired object data if you’re using nested repeaters. It allows you to access the current object of the current or parent loop (if the parent is subsequently named). When you specify a var attribute, the object being iterated over will be stored in the variable name (e.g., ${MyActivities}) as well as within ${Cur}.

For instance, let’s assume that we have the same activity data within the activities object for each one of the user’s friends, stored in the variable friends. Our friend data object contains the name of the friend and an association to the activity data. We may want to display an unordered list of activities for each friend, using multiple repeaters:

<div repeat="${friends}" var="myFriends">
   <b>Activities for ${myFriends.name}</b>
   <div repeat="${activities}" var="myActivities">
      <a href="${myActivities.url}">
         ${myActivities.title}
      </a><br />
      ${myActivities.body}
   </div>
</div>

Using var names, not only can we ensure that we are accessing the exact data that we want, but we also keep our template code readable so that when we’re working with it later, we can follow the object references more easily than if we’d used ${Cur} throughout.

Specifying an index variable for the repeater

Using the ${Context} special variable is handy for capturing the index of the current object being iterated over, but what if you are working with nested repeaters and want to access the indices for both loops within the inner loops? Support for this type of functionality is valuable if you are working with a grid interface for your application, separating loops into x and y planes.

This type of problem is exactly what custom indices attempt to solve. Using the index attribute on a repeater will allow you to access that variable at any point within the loop structure:

<div repeat="${xplane}" index="x">
   <div repeat="${yplane}" index="y">
      <span id="${x}_${y}">
         Current grid index is ${x} : ${y}
      </span>
   </div>
</div>

We apply CSS styles to build a visual grid of our divs. Using the index values, we can then keep track of which grid section we are currently in. These indices can be applied to the id attributes of the divs, for instance, to give us tracking capabilities.

Looping with context

During the course of a loop, you may need to use or collect the current index of, or the total number of results available within, the looped object. This is the purpose of the special variable ${Context}. As we discussed earlier, ${Context} contains three reference objects you can use within the context of a loop:

UniqueId

A unique identifier for the current template being processed

Index

The index number of the current object being iterated over

Count

The total number of objects to be iterated over

Using this special variable, you can add another dimension to the markup to be generated from the loop:

<ul>
   <li repeat="${activities}">
      Activity ${Context.Index + 1} of ${Context.Count}<br />
      <a href="${Cur.url}">
         ${Cur.title}
      </a><br />
      <div id="${Context.UniqueId}-${Context.Index}">${Cur.body}</div>
   </li>
</ul>

In the preceding template, we apply the ${Context} variable to the existing template markup that we built earlier. When this result renders, the user will be presented with markup containing the current index number (e.g., Activity 1 of 10) above every activity that is generated:

<ul>
   <li>
      Activity 1 of 3
      <a href="http://www.twitter.com/jcleblanc">
         Jonathan just added a new comment on Twitter
      </a>
      <div id="tpl1234-1">
         See what Jonathan is saying by adding him to Twitter
      </div>
   </li>
   <li>
      ...

Looping with conditionals

One of the best methods for customizing a loop structure is to apply conditional statements to the loop itself, specifying that you want the loop to run only if a specific condition has been met. Repeaters will be evaluated before conditionals, meaning that when a conditional is used within a repeater, the conditional will be applied to each result within the repeating data set, much like running a standard loop with an if statement embedded:

for (var i = 0; i < result.length; i++){
   if (result[i] === "value"){
      //render markup
   }
}

Our first method, using the repeat attribute on the block to be repeated, applies the conditional statement directly within the same node:

<li repeat="${activities}" if="${Cur.url == 'http://www.container.com/messages'">
   <a href="${Cur.url}">
      ${Cur.title}
   </a><br />
   ${Cur.body}
</li>

This would render the markup only for any object whose URL is http://www.container.com/messages.

If we want to use this same type of conditional loop on an os:Repeat tag, we have to implement it in a slightly different manner. os:Repeat does not support repeat or if attributes, so we will need to embed them within the repeater block:

<os:Repeat expression="${activities}">
   <os:If condition="${Cur.url == 'http://www.container.com/messages'">
      <li>
         <a href="${Cur.url}">
            ${Cur.title}
         </a><br />
         ${Cur.body}
      </li>
   </os:If>
</os:Repeat>

These two statements are equivalent in the order of their execution. Using this mix of repeaters and conditionals, developers can build scalable template designs suited to their application needs.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.117.189.228