The Now Platform® Washington DC release is live. Watch now!

Help
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
SlightlyLoony
Tera Contributor

I warned you yesterday that I'd have more to say about the evaluate tag, and today I'm here to deliver on that threatpromise.

Isaac doesn't look exactly thrilled at that prospect. But he should be!

The evaluate tag has a few special features, all worth understanding. They're the kinds of things that you won't always need, but when you need 'em you'll be glad they're there...

First up: the var attribute. Here's a sample that I'll explain in a second:


<?xml version="1.0" encoding="utf-8"?>
<j:jelly>
<g:evaluate>
var random = 1 + (Math.floor((new Date().getTime() ${AMP} 0xffff) * Math.random()) % 6);
random;
</g:evaluate>

Your rolled: ${jvar_die}
</j:jelly>

Each time you run this page, it will roll a "virtual die" for you, and tell you the result. First, note that we've added the var="jvar_die" attribute to the evaluate tag. That attribute tells Jelly to assign the result (more on that in a second) of the JavaScript inside the evaluate tag to the Jelly variable named in the var attribute (in our case, jvar_die.

The result is simply the value of the last statement in the JavaScript. The style you see here (where we made the last statement simply be the variable containing our result) is a simple, readable way to ensure that the result is what you want it to be. Try taking that statement out to see what happens! In this example, we could just as well have left that var out altogether, and just referenced the random JavaScript variable directly with the JEXL (${random}). But sometimes it's useful to have the result of an expression in a Jelly variable, and this is how you do it.

In this example, if you'll look closely, I did something that just yesterday I told you to avoid like the plague: I used JEXL inside the JavaScript! Bad Loony, bad Loony! Wait a minute...not so fast. This is actually an example of an exception to my rule. Let me 'splain... The general problem with using JEXL inside an expression is that (usually) the result of a JEXL expression is potentially different every time you execute it. That's the actual cause of the problem we're trying to avoid when I tell you "Don't use JEXL inside the evaluate tag!" But in this case (and darned few others!), the JEXL expression will evaluate to exactly the same thing, each and every time. And in this solitary case, it's actually ok to use JEXL inside an evaluate tag. Whew! Loony is off the hook!

Next you might be wondering why on earth we have that JEXL in the first place. Here's why: that math expression needs to use the bitwise AND operator in JavaScript. That operator happens to be an "&" — and that is a reserved character in XML. We're not allowed to write it directly inside an XML document. So instead, we created a constant (AMP) that you can access with JEXL ${AMP} that renders the complicated-looking stuff you'd otherwise have to type in directly (that's &amp;, in case you're wondering — a doubly-encoded HTML entity).

Next up: the expression attribute. Our example:

<?xml version="1.0" encoding="utf-8"?>
<j:jelly>
<g:evaluate/>

Your rolled: ${jvar_die}
</j:jelly>

This one's easy. All I did was to move the code from the body of the evaluate tag up into the expression attribute. Well, that's almost all I did — I also eliminated the random variable altogether, as I never actually needed in the first place (I just wanted to show you how you could use the variable name as the last statement). The expression all by itself serves quite nicely as the result of the evaluate tag. Putting it in the expression attribute is a nice shorthand when the expression is small, simple, and (preferably) a single line. It wouldn't work so well for a larger script, like the one we used for yesterday's example.

Next up: the jelly attribute. Our example:

<?xml version="1.0" encoding="utf-8"?>
<j:jelly>
<g:evaluate/>
<g:evaluate/>

Your rolled: ${jvar_die}
</j:jelly>

For this example, I broke the expression used to calculate the die into two parts. The first part just gets a number based on the current time (in milliseconds). The result of that first evaluate tag is assigned to a Jelly variable — which then I want to use in the second evaluate tag. By default, the Jelly variables are not visible to the JavaScript inside an evaluate tag. By adding the jelly="true" attribute to an evaluate tag, that changes: now the Jelly variables are available, using the syntax you see in my example: jelly. followed by the Jelly variable's name.

Last up: the object attribute. Example:

<?xml version="1.0" encoding="utf-8"?>
<j:jelly>
<g:evaluate>
var dice = new Packages.java.util.ArrayList();
for (var i = 0; 10 > i; i++) {
var die = 1 + (Math.floor((new Date().getTime() ${AMP} 0xffff) * Math.random()) % 6);
dice.add(die.toFixed(0));
}
dice;
</g:evaluate>

Your rolled:
<j:foreach>${jvar_die} </j:foreach>

</j:jelly>

This slight modification rolls our virtual die 10 times, then reports the results all at once. Inside the evaluate tag, the script creates an instance of the Java class ArrayList, then adds the 10 rolls of the die to it. We want the result of this evaluate tag to be that object (the ArrayList instance) so that we can iterate over it with a forEach tag down a couple lines in the Jelly template. This is where the object attribute comes in. By default, the object attribute is false. In this mode, the result of the evaluate tag is converted to a string. If the result happens to be an object of some kind, that object's toString() method will be called to make the string. The result of this is, of course, just a string — and the forEach tag couldn't iterate over it. To deal with these situations, just set the object attribute to true, as in our example here. Then the result of the evaluate will be the actual object instance (in our case, the ArrayList instance), and the forEach tag will be a happy camper.

One little quirk of the forEach tag that I forgot to mention yesterday: the collection that you iterate over (the one in the items attribute) must be a Java Collection — it does not work with JavaScript arrays, in particular — annoying, but unfortunately true...

Well, that's about enough Jelly for one day, don't you think, Isaac?

3 Comments