Expressions

One problem with the last example – the population number. Printing out a number like 63230000 just looks a bit daft.

Step 1

We could replace the number with a string, like '63.2 million'. But numbers are generally a hell of a lot easier to work with.

Instead, we can use an expression. Expressions look just like regular mustaches:

{{ format(population) }}

Add a format property alongside the country data (it may seem weird adding a function as 'data', but it will make sense in due course!):

function ( num ) {
  if ( num > 1000000000 ) return ( num / 1000000000 ).toFixed( 1 ) + ' billion';
  if ( num > 1000000 ) return ( num / 1000000 ).toFixed( 1 ) + ' million';
  if ( num > 1000 ) return ( Math.floor( num / 1000 ) ) + ',' + ( num % 1000 );
  return num;
}

Execute the code. Doesn't that look better? Try changing the values.

ractive.set({
  country: 'China',
  population: 1351000000
});

Note that expressions are not part of the mustache syntax – they are specific to Ractive.js.

Step 2

You can also use mathematical expressions. Let's rummage around in the bag of contrived examples and see what comes out... yep... this one will do... it's a shopping basket.

We have an item property, a price, and a quantity. Add an expression where the total should go:

<td>{{ price * quantity }}</td>

Execute the code. The total should appear. Now we just need to add a currency formatter – here's one for the UK (if you're not from here, write one for your own currency for extra credit):

function ( num ) {
  if ( num < 1 ) return ( 100 * num ) + 'p';
  return '£' + num.toFixed( 2 );
}

Add that, and use in the template it for both the price and the total. Try changing the price and the quantity.

ractive.set({
  item: 'banana',
  price: 0.19,
  quantity: 7
});

You might reasonably ask how this works. What happens is this: when the template is parsed, any references inside expressions (such as price, quantity or format in the example above) are identified. At render time, the expression binds to those references and creates a function to calculate the result. (Whenever possible, Ractive.js will re-use functions – for example {{a+b}} and {{c+d}} would share the same function.)

When the value of one or more of those references change, the expression is re-evaluated. If the result changes, the DOM is updated.

Step 3

In this next contrived example, we're going to make a colour mixer.

First, we want to show how much we're using of each colour. We'll use <div> elements with a percentage width corresponding to the amount. All the colour values are between 0 and 1, so we need to multiply by 100:

<div style='background-color: red;
     width: {{red*100}}%;'></div>

Update the first three <div> elements in the template accordingly.

Pro-tip: in the playground editors, hold the Cmd key (or Ctrl if you're not on a Mac) and click in each of the places where you need to type 100. Multiple cursors FTW!

To show the result, we can use an rgb(r,g,b) CSS colour value. But instead of percentages, these need to be between 0 and 255:

<div style='background-color:
  rgb({{red   * 255}},
      {{green * 255}},
      {{blue  * 255}})'>
</div>

Update the template and execute the code. Did it work?

No, it didn't. That's because CSS insists that you use integers – no decimals allowed. So let's use Math.round to turn the numbers into integers:

<div style='background-color:
  rgb({{Math.round(red   * 255)}},
      {{Math.round(green * 255)}},
      {{Math.round(blue  * 255)}})'>
</div>

Execute the code. Ta-da! Try changing the colours.

ractive.set( 'red', 1 );
// PSST! Want a sneak preview of something neat?
// Try using ractive.animate() instead of ractive.set().
// You can drop it in after the line 9 in the Script content.

The Math object is one of several built-in JavaScript objects you have direct access to within expressions, alongside Date, encodeURI, parseInt, JSON and various others. Consult the documentation for a full list. You can also access other globals using the @global special reference, where the JSON object would be accessible as @global.JSON.

Expressions can be as simple or as complex as you like, as long as they only refer to properties of their view model (i.e. the properties on the data object), don't include assignment operators (including +=, -=, ++ and --), new, delete or void, and don't use function literals.