Not-So-Easy Like Friday Morning

Creative Commons License photo credit: Or Hiltch

This took a whole day for me. Hopefully I can save you the pain. I added quite a few possible search terms here for maximum coverage, so the text may get a bit repetitive. I mean – when I tried to look for a solution, I didn’t even know what to look for – so I tried googling for every symptom I saw, to no avail.
The deal was this: my page has a very large form, which is logically separated to 3 parts.
One part is mandatory, and the user must fill in all the fields on it. However, the other two parts are completely optional, and it is quite possible that some users won’t even bother with one or both of them (See the uber useful diagram below)

Form with mandatory and optional parts

Normally, you’ll split this form into a wizard type of thing, but again – some users may not use the optional parts at all, and anyway – we don’t do wizards.

Because of the form’s size, I didn’t want the optional parts to appear alongside the main part on the page. This would have made the page huge. So, I came up with the brilliant idea to have them hidden (wrapped with a <div> element with style=”display:none”) and display them with fancybox. (See the next beautifully decorated diagram!)

Form with hidden div

So the idea is pretty simple. The user interacts with the mandatory part, and if they need one (or both) of the optional parts, they can click the links that read ‘Open optional part…’. These links have inline hrefs to the optional form parts which are inside the hidden div. (Each of these optional parts is contained in a div of its own, to make it easier for fancybox).

In document.ready() – I fancybox both these links. Which means that when they are clicked, their reference will open inside fancybox. This actually worked quite well and I was very happy.
Until I tried to save the data, and it wasn’t there. At least not all of it.

First issue: Form fields missing when submitted

Since I knew I wasn’t getting all of the form fields in my controller, I wanted to see what the browser was sending back on submit. Using firebug’s net tab, I got a little surprise.
if the user clicked on one of the links to display an optional part, the entire set of fields contained in the optional part was missing from the POST request.
The mandatory fields were always sent. But with regards to the optional parts – only the fields that were a part of an optional part that was not displayed (using fancybox) were sent back on submit.

Now, this is an outrageous behaviour. Theoretically, only disabled fields should be omitted from a submitted form, but none of my fields was being disabled.

Just to make sure, I changed the visibility of the containing <div> element, so that my optional parts showed all the time, and tried to submit the form. Everything was fine. But when I clicked on one of the links to display them (with fancybox) – I got the same behaviour.

Using jquery’s serailizeArray() showed that the fields were all there on page load, but disappeared right after the optional parts were fancybox’d.

Second issue: Fancybox ignores custom configuration

Alongside the issue of the missing fields, I wanted to manually control the size of fancybox’s overlay for one of the optional parts. This is normally quite easy:

$("a#openOptionalOne").fancybox({
    'width':900,
    'height':800,
    'autoScale':false,
    'autoDimensions':false
});

The only thing you have to remember is that if you want to manually set height and width, you have to give both height and width. Also, you have to set both autoScale and autoDimensions to false.
However, fancybox didn’t care too much about my directives and refused to change its default rendering. I should have taken this as a warning, but since my form fields were disappearing on submit – I decided I have more urgent things to solve.

A middle-of-the-road moral here:

When Fancybox doesn’t do what you know it should do – there’s something wrong. Fix this first.

I was on a role with my form-issues, and disregarded this warning. Oh well.
Now, at this point, I could have just decided to go for a workaround: Use a wizard, make each of the optional parts a form unto itself, or just decide to display the entire form on one page (there are other visual tricks to use, but this is in the next post).

But no. I was on a mission to find out why fancybox removes my fields away. Seriously. Workarounds are good, but if I have the time – I’d rather get down to the bottom of it.

Could fancybox have changed my DOM?

A friend suggested that fancybox may have changed the DOM somehow. So I console.log’d document.body.innerHTML before fancybox and after fancybox (without changing any of the optional form fields).
Copied them into a couple of variables and compared:

# -*- coding: iso-8859-15 -*-
orig= '''
<div...............................
'''


postfancy = '''
<div..............................
'''

for x, y in map(None, orig, postfancy):
if (x!=y):
  print 'ahoy there!'
  break

Both were the same. So no visible mucking around (still, there could be issues with the DOM being manipulated, but it’s not that simple).

Third issue: Fancybox ignores custom configuration (I know… again)

To try and see what’s going on, I thought I’d hook on to fancybox’s onCleanup event. The onCleanup event gets called just before fancybox closes. I wanted to use it to display my form’s content- but as happened before, fancybox ignored me completely.
Now, second time you get the same warning – this is time to pay some serious attention.

First thing to try – ensure I’m on the latest version of fancybox (note – I know that there are no compatibility issues, because fancybox works perfectly on another page, where the entire form is contained within it).

Indeed, I had v1.3.1 and 1.3.4 was out. (fancybox v2 is great, but the license has changed so I can’t use it).

But upgrading did not change behaviour, so I downgraded back (this is important, I think. While it is usually good to upgrade, don’t blindly do it if it didn’t solve your issue. If a library upgrade did not affect the defect at hand – might as well reverse it and try solving the issue first – then go with the upgrade. Any upgrade can introduce new bugs that may obscure your initial problem).

Just to make sure I wasn’t losing my mind, I changed the default configuration options inside fancybox’s javascript (you can do it too – they are right at the bottom of the file).
This worked – I could hook onto the onComplete event or change the width and height. This meant to me that the issues I was having of fancybox ignoring my configuration or my form fields disappearing weren’t likely to stem from fancybox, but rather from my code.

When all else fails – RTFM

So, it’s off to the how-to page on fancybox’s website.
Now, here’s where I failed…

Fancybox requires a valid doctype

See, the problem is that while my document indeed had a valid DOCTYPE, it did not validate accordingly.
Sifting through the generated code, I found that the end </form> tag was badly placed. In essence I had the following structure:

..
<form...>
    <div>
        <input....>
        <input...>
        <input type="submit"...>
        </form>
   </div>
..

See the problem? my form closed before a contained div element closed. While this works well (and has been for at least a year’s worth of browsers upgrade), when Fancybox was thrown into the mix it simply refused to accept this sorry state of affairs.

Fix your pages…

To confirm my suspicion and mock my HTML abilities, the issue was gone once the page validated completely, and I am now the proud owner of a form that has hidden optional parts that appear inside a fancybox wrapper when you click on links. Hooray!!

Form with hidden div

Popularity: 1% [?]

 

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>