SlightlyLoony
Tera Contributor

Throughout this series, I've been using UI Pages as my examples — but to this point I haven't mentioned one of the main purposes that people want UI Pages: the ability to interact with a user. So today I'm going to show you a very simple example of how that might be done. I've deliberately kept this example stripped to the basics in order to highlight the bits I'm showing you. In the world of HTML, that means it's ugly as sin — try to ignore that (or fix it up yourself!) and concentrate on the mechanics.

Our goal today: we need an order form for hamburgers, for our very simple gourmet hamburger business. Our chef will let you ask for anything you want on your burger, but he delivers it the way he decides to. The burgers are a fixed price: $27.89 (they're really good!), which is about the same in Euros these days. So our order form needs only one input: the number of burgers you want. When you submit your order, we compute the extended price, the tax (8.75% here in San Diego), and the total. Here's the example page, which is named order_form:


<?xml version="1.0" encoding="utf-8"?>
<j:jelly>
      <g2:evaluate>
              var isAnswer = (jelly.sysparm_answer != null);
              isAnswer;
      </g2:evaluate>
      <j2:if>
              Number of burgers you want: <input id="number_of" type="text" />

              <input id="enter_number" type="submit" />
                            $('enter_number').onclick = function(event) {
                            window.location = 'order_form.do?sysparm_answer=true${AMP}' +
                                      'sysparm_number=' + $('number_of').value;
                    }
           
      </j2:if>
      <j2:if>
              <g2:evaluate>
                      var qty = jelly.sysparm_number - 0;
                      var ext = qty * 27.89;
                      var tax = ext * 0.0875;
                      var tot = ext + tax;
                      var extStr = ext.toFixed(2);
                      var taxStr = tax.toFixed(2);
                      var totStr = tot.toFixed(2);
              </g2:evaluate>
              Your delicious burgers will be ready shortly after you fork over the cash.   You owe us:

              $[extStr] for the burgers

              $[taxStr] for the tax man

              $[totStr] due to us, now, in small unmarked bills and coins
      </j2:if>
</j:jelly>


Most of that you should be able to understand right now. The only thing I've really added to the Jelly is a couple of Jelly variables whose names start with sysparm_ instead of jvar_ (but they're Jelly variables nonetheless). More on those a little further along in this post. Right now I want to tell you a little bit about how UI Pages actually work in the ServiceNow system.

When you define a UI Page, you define more than the Jelly — you also give that UI Page a name (and there are other fields that I'm not going to describe today). That name is how you get the UI Page to display — it becomes part of the URI. For example, I named this UI Page order_form, and to ask for it I use the URI /order_form.do. The ".do" after the UI Page's name is the standard way on the ServiceNow platform to construct a URI that runs a UI Page (or other things, but those are topics for another day). It's important that the name you pick for your UI Page be different than the name of any other UI Page or other valid URI, otherwise you might get something unexpected when you use that URI!

Just like any other URI, you can include query parameters in your ServiceNow URIs. But...there's a convention you need to follow to make these query parameters available to your Jelly pages — the names of those query parameters need to start with sysparm_. When they do, the ServiceNow platform will automagically copy them into Jelly variables — those same Jelly variables that I mentioned earlier. So, for example, a URI that looks like this:


/order_form.do?sysparm_answer=false&sysparm_number=5


Will result in two Jelly variables appearing in your order_form UI Page: sysparm_answer (with a value of "false") and sysparm_number (with a value of 5).

Now, armed with this knowledge, take a close look at the example Jelly above. The first evaluate tag is just testing to see if the sysparm_answer parameter was present. If we request the order_form UI Page with no query parameters, then the result of this evaluate will be false; otherwise it's true:


      <g2:evaluate>
              var isAnswer = (jelly.sysparm_answer != null);
              isAnswer;
      </g2:evaluate>


Just after that evaluate, we have a couple of if tags. Check out what they're doing:


      <j2:if>
              ...
      </j2:if>
      <j2:if>
              ...
      </j2:if>


Basically they divide our single UI Page into two: one that renders if there wasn't a sysparm_answer parameter, the other if there was. Now let's look inside the piece that only renders when there is no sysparm_answer parameter:


              Number of burgers you want: <input id="number_of" type="text" />

              <input id="enter_number" type="submit" />
                            $('enter_number').onclick = function(event) {
                            window.location = 'order_form.do?sysparm_answer=true${AMP}' +
                                      'sysparm_number=' + $('number_of').value;
                    }
           


This just puts up a really dumb little form to capture the number of burgers the user wants to order. But look in the script: when the user clicks on the submit button, that script constructs the URI to go right back to our order form — but this time with query parameters. Now let's look at the piece that only renders when there are query parameters:


              <g2:evaluate>
                      var qty = jelly.sysparm_number - 0;
                      var ext = qty * 27.89;
                      var tax = ext * 0.0875;
                      var tot = ext + tax;
                      var extStr = ext.toFixed(2);
                      var taxStr = tax.toFixed(2);
                      var totStr = tot.toFixed(2);
              </g2:evaluate>
              Your delicious burgers will be ready shortly after you fork over the cash.   You owe us:

              $[extStr] for the burgers

              $[taxStr] for the tax man

              $[totStr] due to us, now, in small unmarked bills and coins


In this evaluate tag we compute the extended price, the sales tax, and the total. Just below that, we render the results so that our customer can pay us.

What I did here with a single UI Page could just as easily have been done with two completely separate UI Pages — which way to go is a design choice that's entirely up to you. Generally I prefer the page-for-each-function style (which would take two pages here), but your mileage may vary.

So there you go — UI Pages that actually interact with a user! What more could you possibly want?

14 Comments
jacob_kimball
ServiceNow Employee

SL,

You include a form element here....do you get the

html wrapper for free in UI pages or with a more extensive page/form would you want to include that and is there a SNC widget to do that? If there is a widget I am assuming you can feed it the next page that you want to submit too?


tony_fugere
Mega Guru

Did I glance over something in the Wiki or is this missing?


jelly="true"
plus

jelly.sysparm_answer
is about 1000 times easier than

RP.getParameterValue('sysparm_answer');
.

Yet another awesome, informative post! Thanks, Tom!


Oliver D_sereck
Giga Expert

I have been using the RP.getParameterValue('sysparm_answer'); too, good to know about the sysparm_ variables.

Thanks SL!


dmartinc
Tera Expert

The thing with RP.getParameterValue() is that you can call your URL parameters in any way you want, so they do not need to start with sysparm_
If the parameters of our CMS all started with sysparm_ , we would get a lot of complaints about URL length and readability... we get them even if the parameters do not have sysparm_ in them! 🙂


tony_fugere
Mega Guru

Agreed! It has it's benefits, but I won't be "wasting" my precious typing with it for sysparm_'s anymore... 🙂


bennyb
Kilo Contributor

Loving these tutes

Hi Slightly Looney,

Just some quick props - loving the these Jelly tutes, they helped me get a quick understanding of Jelly in the context of SN.

Perhaps your examples could be added to the wiki doco as this is usually the first place I look for info.

Keep up the great work!

Benny


Slava Savitsky
Giga Sage

These articles are just awesome!

Hi SlightlyLoony

First of all, thanks a lot for the great series of Jelly articles! They are very helpful indeed as this kind of information does not seem to be available elsewhere.

In the example above, you used standard HTML tags to build a form. However, there seems to be a set of special Jelly tags that developers can use to create nice looking forms having that familiar ServiceNow look and feel:



<g:ui_multiline_input_field />
<g:ui_checkbox />
<g:dialog_buttons_ok_cancel />
etc.

And each of these has its own bunch of attributes, which one can only figure out by digging into OOB UI pages and macros. I wonder if this could become a subject for one of the future articles.

Thank you! And Merry Christmas!


DrewW
Mega Sage

What if you would like the user to pick something from a dropdown and then reload the page filtering the data based on the dropdown item selected? Would you just use a button to redirect the user to the same page and set the sysparm_whatever or is there a better easier way?


tony_fugere
Mega Guru

In short, yes

Yes, your page reload would be an "easy" way to implement that and that is how the list view works today. If you make your custom drop-down intelligent enough to pass the sysparm_query URL parameter with the proper encoded query, then ServiceNow will do all of the "hard" work for you in filtering the list.


Akshat Chawla
Giga Expert

I have a query !

Hi

If I want the result should be visible on the same UI page itself. How can I achieve this.???


Thanks