Posted by: Brendan Long | October 18, 2014

Show/hide content based on a checkbox – and why you have to do it client side

Today’s basic XPages coding adventure sees our hero start from the depths of dodgy and make his way towards the light – quite refreshing really, because most of the time I’m moving in the other direction.

The Problem

The problem is a typical situation that everybody sees from time to time – a checkbox in a form table that shows a few extra rows if you check it.  Simple stuff, really.

Picture of a checkbox that is used to hide some additional fields

Too easy!

Everything is in the Extension Library Form Layout Rows for convenience, and the date fields are Dojo Date Text Boxes.  Start Date is mandatory, with a validateRequired validator on it to handle this.

Starting off, feeling lazy, I went with the simple solution.  Partial refresh from onClick in the checkbox, with the rendered property on the last two form layout rows setting the visibility depending on the value of the checkbox control.  Voila – it worked.  Too easy!

Until I tested it properly.  What if your user, bless them, decides to check the Create Repeats checkbox before setting a date?  I know this seems completely illogical, but who are we to judge?

InvalidError

The Dojo Date Text Box does some nice helpful client side validation, which prevents anything server-side going ahead…..which of course prevents your server side rendering from bringing up the additional rows.  Oh no!  Your checkbox stays checked too, which means that your user is now stuck.  The only way they can get the repeat fields to appear is to fill in the date, uncheck the checkbox and check it again, no doubt while reaching new heights of righteous indignation and venting to your manager.

OK, so maybe we should do this better.

Client Side!

Doing this on the client side is the obvious solution here, and it is of course the right way to do anything like this when you’re not being dodgy and lazy.  display: none.  Thanks Captain Obvious.

However, it is better to use classes for this, so I set up a couple of simple classes in my CSS:

.repeatInvisible {
     display: none;
}
.repeatVisible {
}

Why did I create a blank style for the visible case?  Don’t worry, there’s method to the madness here.

First up, we need to set the styleClass on the hidden form rows to make sure the initial value of the class gives the right value when the XPage is first rendered:

var hideStyle = getComponent("repeats").getValue() == "Y" ? "repeatVisible" : "repeatInvisible";
return "lotusFormFieldRow " + hideStyle;

Next, the onChange event on the checkbox – client side script.  There’s a little gotcha here – Form Layout Rows render as a <tr> tag with your class applied, but no id attribute.  You can’t use dojo.byId(“#{id:formRow8}”) here, so you need to find the rows that have your custom classes on them and manipulate the styles from there.  This is why you need the blank class – so that you’ve still got something there to identify your rows if you need to hide them again.

var repeats = dojo.byId("#{id:repeats}");

if(repeats.checked){
   dojo.query(".repeatInvisible").forEach(function(node, index, nodelist){
      dojo.toggleClass(node, "repeatInvisible");
      dojo.toggleClass(node, "repeatVisible");
   });
}else{
   dojo.query(".repeatVisible").forEach(function(node, index, nodelist){
      dojo.toggleClass(node, "repeatInvisible");
      dojo.toggleClass(node, "repeatVisible");
   });
}

There are obviously lots of other ways to get at the classes and change them, but I like the way dojo makes things simpler here and allows you to hide any number of rows in one hit.  Pedants will point out that you probably don’t even have to use a conditional statement on the checkbox – you could just add an additional dummy class to the rows to make the search work and toggle the classes without checking the state.  True, but I wanted to make sure there was no way possible that you could somehow get out of whack and start toggling them in the reverse order.  I don’t actually know how that could happen, but computers have a talent for the unexpected – especially when I’m writing the code.

Lastly, you can remove any client side code or partial refresh stuff from your onChange event if you’re not doing anything further – you’re home and hosed!


Responses

  1. Glad to see you are still blogging 🙂

    thanks for sharing 🙂

  2. What if you just set the event that the checkbox triggers to “not validate” in the options? Then you should be able to to it server side.

  3. From memory I tried all the options for disabling validation and couldn’t get it working. I’m not confident enough to say that it won’t work, but I couldn’t get it to. 🙂

    I just threw together a quick test page and tried it with “Process data without validation” ticked on the event handler for onchange on the checkbox – the client side validation on the dojo date control still triggers with this option selected – and prevents the partial refresh. There might be something on the dojo date field that you could set to make this stop (dojo attributes maybe?), but I didn’t dig that deep.

    In the end, after a couple of dead ends I chucked it in and went client side. 🙂


Leave a comment

Categories