loading forms via AJAX

78 views
Skip to first unread message

freerick

unread,
Sep 22, 2010, 7:47:22 PM9/22/10
to Ubiquity XForms Developers (Users)
I have a page with a drop-down menu and a form. The item that is
selected from the drop-down menu shall determine which form is shown
to the user. I must use AJAX to load a new form each time a new item
is selected from the drop-down menu. The AJAX response is xforms xml
and I want ubiquity to transform the xforms markup to browser-
compatible html / javascript after each AJAX request completes.
I noticed that ubiquity does most of the decoration work onDOMReady so
out of the box, my AJAX-loaded xforms XML does not get parsed. I tried
to determine which events fire onDOMReady and manually dispatched
those actions in my AJAX callback. However, this only works for the
first form. Subsequent forms are rendered, but the validation / enable/
disable events are not attached properly.

My other issue with the approach is form submission. We want the forms
not only to be rendered via AJAX but we also want to handle the
submission via AJAX. In other words, the user should never leave the
page they are on. How can I manually hook into the ubiquity form
submission events without triggering a page reload?

Frankie Dintino

unread,
Sep 23, 2010, 9:21:50 PM9/23/10
to ubiquit...@googlegroups.com
Hi freerick,

Rather than tearing down the rendered xform instance, reloading, and simulating a DOM-ready event, have you considered loading the xforms within an iframe? That would be the least fraught way of dynamically loading/switching an xform.

If you don't want a scrollable iframe and wish to make it appear as if the form is loading onto the page itself, you could dynamically resize the height of the iframe element to give the appearance that it's a normal block element (a quick google found this jquery plugin <http://www.lost-in-code.com/programming/jquery-auto-iframe-height/>).

Regarding your second question: if I remember correctly, an xforms submission doesn't cause a reload of the containing document by default (if you set the <submission> replace="all" it will replace the entire page with the contents of the submission response, but it defaults to replace="instance" if unspecified).

If you wish to do some additional javascript processing after a submission completes, you can attach to the "xforms-submit-done" event. The most common way of doing this is to use an <action> element inside the <submission>:

<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:xf="http://www.w3.org/2002/xforms"
xmlns:ev="http://www.w3.org/2001/xml-events">
<head>
<script type="text/javascript">
// <![CDATA[

function processSubmit() {
// ajaxy stuff
}

// ]]>
</script>
</head>
<body>
<xf:model id="my-model">
<xf:instance id="main-instance">
...
</xf:instance>
<xf:submission id="submit" method="..." ...>
<xf:action ev:event="xforms-submit-done">
<xf:load resource="javascript:processSubmit()"></xf:load>
</xf:action>
</xf:submission>
</xf:model>

...

</body>
</html>

Alternatively, you can do the same thing as the <action> above using javascript by attaching a handler to the xforms model element on the 'xforms-submit-done' event.

Best,
Frankie Dintino

> --
> You received this message because you are subscribed to the Google Groups "Ubiquity XForms Developers (Users)" group.
> To post to this group, send email to ubiquit...@googlegroups.com.
> To unsubscribe from this group, send email to ubiquity-xfor...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/ubiquity-xforms?hl=en.
>

freerick

unread,
Sep 29, 2010, 1:45:00 PM9/29/10
to Ubiquity XForms Developers (Users)
Frankie,

thank you for your reply. Due to the way the rest of our interface was
designed, the AJAX call was almost a hard requirement and the iFrame
approach was a last resort.
I was able to successfully use the AJAX call, however there were a few
caveats: when switching from one form to another via AJAX, ubiquity
was always using the model from the first form that loaded instead of
the current form, which was causing problems. I was able to resolve
this by explicitly setting the model property on the xf:bind and
xf:input elements.

Regarding the submission handling, I was unable to use the method that
you had suggested because it looks like the callback function that is
called as a result of the xforms-submit-done event does not receive
the data that gets sent back from the server in response to the AJAX
call, or at least I was unable to figure out how to access it. It does
seem to be getting passed the headers from the response in the
callback but not the body. I was able to work around this for now by
overriding the submission communications class with my own
implementation, instead of using the default YUI-based class. That way
I was able to directly access the ajax call process in order to
capture the response body and process it as needed.

Perhaps you have more insight here regarding how to access the
response body in the xforms-submit-done callback? Maybe I'm just
missing something here...

Thanks!

Frankie Dintino

unread,
Sep 29, 2010, 8:35:03 PM9/29/10
to ubiquit...@googlegroups.com
There are a few ways to do this without changing the ubiquity xforms js files. The approach I would take is marked up below. The "submit-w-txt-response" submission calls a function that gives you the contents of the response as a string (useful if you're returning json) and the "submit-w-xml-response" submission calls a function that gives you a Document for the response. Somebody else can chime in if they know of a way that doesn't involve a uxf-specific javascript call.

I also discovered a bug while drawing up this example, so until that's fixed make sure that your "response" instance has at least one child node (a space between the instance tags will do).

<html>
<head>
<script type="text/javascript">/* <![CDATA[ */
function getInstanceDoc(instanceName) {
var model;
var isXHTML = (document.xmlVersion || (document.contentType && document.contentType === "application/xhtml+xml"));
if (isXHTML) {
model = document.getElementsByTagNameNS("http://www.w3.org/2002/xforms", "model")[0];
} else {
model = document.getElementsByTagName("xf:model")[0];
}
var instance = model.getInstanceDocument(instanceName);
return instance;
}

function submitDoneText() {
var responseDoc, responseText;
responseDoc = getInstanceDoc('response');
// Grab the nodeValue of the instance's root element
if (responseDoc.documentElement && responseDoc.documentElement.firstChild) {
responseText = responseDoc.documentElement.firstChild.nodeValue;
}
}

function submitDoneXml() {
var responseDoc = getInstanceDoc('response');
// We're done!
}

/* ]]> */</script>
</head>
<body>
<xf:model xmlns:xf="http://www.w3.org/2002/xforms" id="xforms-model">
<xf:instance id="main">
...
</xf:instance>
<xf:instance id="response"> </xf:instance>

<xf:submission id="submit-w-xml-response"
resource="..."
ref="instance('main')"
replace="instance"
targetref="instance('response')">


<xf:action ev:event="xforms-submit-done">

<xf:load resource="javascript:submitDoneXml()"></xf:load>
</xf:action>
</xf:submission>

<xf:submission id="submit-w-txt-response"
resource="..."
ref="instance('main')"
replace="text"
targetref="instance('response')">


<xf:action ev:event="xforms-submit-done">

<xf:load resource="javascript:submitDoneText()"></xf:load>
</xf:action>
</xf:submission>

</xf:model>
...
</body>
</html>

freerick

unread,
Sep 30, 2010, 8:02:19 PM9/30/10
to Ubiquity XForms Developers (Users)
Thank you Frankie!
I will give this a try and let you know how it worked out.

--Patrick

freerick

unread,
Oct 1, 2010, 7:09:31 PM10/1/10
to Ubiquity XForms Developers (Users)
Frankie,

your approach worked in that I was able to retrieve the response text
in my callback handler. Thank you for that!
However, I would like to point out that the following code did not
call the submitDoneText() the event:

<xf:action ev:event="xforms-submit-done">
<xf:load
resource="javascript:submitDoneText()"></xf:load>
</xf:action>

rather, I had to use javascript to bind submitDoneText to the model
element for the xforms-submit-done event in order for it to be called
when the xforms-submit-done event fires.

Could this be a bug?

Best,

Patrick
> ...
>
> read more »
Reply all
Reply to author
Forward
0 new messages