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've briefly mentioned (but didn't really explain) the two types of variables one can find in Jelly templates: Jelly variables and JavaScript variables. My colleague Burton (seen at right while creating a particularly challenging Jelly template) wants to know things. "Why," he asks "would I use a Jelly variable instead of a JavaScript variable? Or vice versa? And whatever those differences are, why on earth didn't you blithering idiots just make it all work with one or the other? Do I have to do it all for you?"

Well, Burt, it's like this:

First, wash your face, bud. You're about to make a serious mess of your keyboard and mouse.

The key to sorting all this out is to realize that there are three different places where variables get used — and of course, what works where is different in each case:

  • Jelly: This may surprise you, but…Jelly doesn't know about JavaScript variables at all. It only knows about Jelly variables. Jelly itself doesn't actually care what the names of Jelly variables are, but nevertheless when using Jelly on the ServiceNow platform, it's vital to start the name of every Jelly variable with the prefix jvar_, which you'll see used throughout the out-of-the-box Jelly templates. In Jelly, this naming convention allows some optimization — but in JEXL (as you'll see below) it is imperative.
  • JEXL: On the ServiceNow platform, JEXL will work with either Jelly variables or JavaScript variable. Standard JEXL only works with Jelly variables, but ServiceNow has extended it to work with both. The mechanism is simple (pay attention, this is important!😞 if the variable name starts with jvar_, JEXL assumes it's a Jelly variable. Otherwise, JEXL assumes it's a JavaScript variable. This has some consequences. For example, if you create a JavaScript variable that starts with jvar_, JEXL won't know it's there. Also, if you create a Jelly variable that doesn't start with jvar_, JEXL won't know it's there. Bottom line: follow the Jelly variable naming convention, and you won't get hurt.
  • JavaScript: Of course JavaScript knows about its own variables — but it can also know about Jelly variables, through the jelly="true" attribute I introduced in an earlier post. There's a catch, though: JavaScript can read (look at the values of) Jelly variables, but it cannot write (change the values of) or create Jelly variables. This happens because of the way that jelly="true" attribute actually works: it copies the Jelly variables into JavaScript variables. You can modify the JavaScript variable all you want — but the changes you make won't be copied back to the Jelly variables.


Here's an example of several easy-to-make mistakes regarding Jelly and JavaScript variables:



<pre style="margin-left:20px;line-height:1;color:FireBrick;">
<?xml version="1.0" encoding="utf-8" ?>
<j:jelly trim="false" xmlns:j="jelly:core" xmlns:g="glide" xmlns:j2="null" xmlns:g2="null">
      <j:set var="jvar_alpha" value="alpha" />
      <g:evaluate jelly="true">
              var colors = ['Red', 'Black', 'Blue', 'Brown', 'CadetBlue', 'DarkGreen', 'DeepPink'];
              var jvar_test = 'test';
              jelly.jvar_alpha = 'ALPHA';
              jelly.jvar_beta = 'BETA';
      </g:evaluate>
      <j:forEach items="${colors}" var="color">
              <g:breakpoint/>
              <p>Color: $[SP] <span style="color:${color};"> ${color}</span></p>
      </j:forEach>
      <p>test: ${jvar_test}</p>
      <p>alpha: ${jvar_alpha}</p>
      <p>beta: ${jvar_beta}</p>
</j:jelly>
</pre>


This goes horribly wrong in several ways. We'll take 'em one at a time:

  • The evaluate tag has the jelly="true" attribute, so the Jelly variable jvar_alpha defined on the preceding line gets copied into the jelly variable (as jelly.jvar_alpha). That part works just fine. In the script we attempt to change the value of that property (with jelly.jvar_alpha = 'ALPHA';. We also try to create a new Jelly variable (with jelly.jvar_beta = 'BETA';). Near the end of the Jelly template, we try inserting these Jelly variables into paragraphs — and if you run this as a UI Page, you'll see that it does not work.
  • Inside the evaluate tag, you can see the line var jvar_test = 'test';. This looks like we're trying to set the value of a Jelly variable, but actually what we're doing is setting the value of a JavaScript variable whose name happens to look like the name of a Jelly variable. Near the end of the Jelly template you can see where we try to insert that variable into a paragraph — and it works very poorly indeed. This fails because JEXL expression ${jvar_test} sees that the name starts with jvar_ and assumes that it's a Jelly variable — one that doesn't actually exist. Fail.
  • Now look at the tag j:forEach items="${colors}" var="color". This is going to iterate over the JavaScript array j:forEach items="${colors}" var="color" and put each value it iterates over into the variable color. It's that variable name that poses a problem: the name coloris a valid Jelly variable name, so Jelly works just fine with it. But a little later (in

    Color: $[SP] ${color}

    ), we use that variable name in JEXL expressions — and those try to look up the value in a JavaScript variable (because the variable name doesn't start with jvar_). This is a good example of a bad thing that can happen because you didn't start a Jelly variable's name with jvar_.

Just for fun, here's the same thing with all the problems fixed. Note the use of JEXL expressions to move JavaScript values into Jelly variables:



<pre style="margin-left:20px;line-height:1;color:FireBrick;">
<?xml version="1.0" encoding="utf-8" ?>
<j:jelly trim="false" xmlns:j="jelly:core" xmlns:g="glide" xmlns:j2="null" xmlns:g2="null">
      <g:evaluate jelly="true">
              var colors = ['Red', 'Black', 'Blue', 'Brown', 'CadetBlue', 'DarkGreen', 'DeepPink'];
              var test = 'test';
              var alpha = 'ALPHA';
              var beta = 'BETA';
      </g:evaluate>
      <j:set var="jvar_test" value="${test}"/>
      <j:set var="jvar_alpha" value="${alpha}"/>
      <j:set var="jvar_beta" value="${beta}"/>
      <j:forEach items="${colors}" var="jvar_color">
              <g:breakpoint/>
              <p>Color: $[SP] <span style="color:${jvar_color};"> ${jvar_color}</span></p>
      </j:forEach>
      <p>test: ${jvar_test}</p>
      <p>alpha: ${jvar_alpha}</p>
      <p>beta: ${jvar_beta}</p>
</j:jelly>
</pre>


I hope that's quite enough on this subject, Burt! Did you wash your face yet?

11 Comments