webtier@glassfish.java.net

JSF2: problem executing scripts in Ajax response (bug-like)

From: <webtier_at_javadesktop.org>
Date: Mon, 08 Mar 2010 06:51:39 PST

I have been doing some experiments with PrimeFaces and I ran into a Mojarra behavior that I think could be improved.

So, I have a page that roughly looks like this:


[b]Listing 1:[/b]

[code]
<h:outputLabel for="inPhone" value="Phone:" />
<p:inputMask id="inPhone" value="#{pfAjax1.phone}" mask="(999) 999-9999"/>
</br>
<h:commandButton value="Submit (Mojarra)">
    <f:ajax execute="form:inPhone" render="form:inPhone form:outPhone" />
</h:commandButton>
<br/>
<h:outputText id="outPhone" value="The phone is: #{pfAjax1.phone}" />
[/code]


(Forget about the specifics of [b]<p:inputMask>[/b] component. It could be some other component. That's not the main point.)

Ok, the page is supposed to get some input into the "inPhone" component and then, after pressing the Ajax-enabled button, to re-render both the "inPhone" and "outPhone" components.

The [b]<p:inputMask>[/b] component has generated the following markup:


[b]Listing 2:[/b]

[code]
<script type="text/javascript">
  PrimeFaces.onContentReady('form:inPhone', function() {
  jQuery(PrimeFaces.escapeClientId('form:inPhone')).mask('(999) 999-9999')});
</script>
<input id="form:inPhone" type="text" value="" name="form:inPhone" />
[/code]


After pressing the button, the Ajax response (reformatted for better readability) is:


[b]Listing 3:[/b]

[code]
<?xml version="1.0" encoding="utf-8"?>
<partial-response>
  <changes>
    <update id="form:inPhone">
      <![CDATA[<script type="text/javascript">PrimeFaces.onContentReady('form:inPhone', function() { jQuery(PrimeFaces.escapeClientId('form:inPhone')).mask('(999) 999-9999')});</script>
      <input id="form:inPhone" name="form:inPhone" type="text" value="(123) 456-7890" />]]>
    </update>
    <update id="form:outPhone">
      <![CDATA[<span id="form:outPhone">The phone is: (123) 456-7890</span>]]>
    </update>
    <update id="javax.faces.ViewState">
      <![CDATA[-6233500061702692391:-3100442592004256570]]>
    </update>
  </changes>
</partial-response>
[/code]


So, the response contains a script that must be executed at the client. [b]But it does not get executed at all.[/b]

After some investigation, I found the following fragment in [b]jsf.js[/b], starting from line 927:


[b]Listing 4:[/b]

[code]
                        ...
                        runScripts(scripts);
                    } else if (d.nodeName.toLowerCase() === 'input') {
                        // special case handling for 'input' elements
                        // in order to not lose focus when updating,
                        // input elements need to be added in place.
                        parserElement = document.createElement('div');
                        parserElement.innerHTML = html;
                        newElement = parserElement.firstChild;

                        cloneAttributes(d, newElement);
                        deleteNode(parserElement);
                    } else if (html.length > 0) {
                        ...
                        runScripts(scripts);
                    }
                    ...
[/code]


The [b]runScripts(script)[/b] function does [b]NOT[/b] get invoked for INPUT elements. But, as we see in [b]Listing 2[/b], [b]"form:inPhone"[/b] is exactly an INPUT element. So, the script does NOT get executed and the component fails miserably. (It's not just the [b]<p:inputMask>[/b] component that fails. Most of them do. I'm just using one of the components as an example.)

So, in PrimeFaces they have abandoned standard JSF2 Ajax and are using their own custom solution. [b]If other libraries go this way, we will have a huge mess of Ajax-incompatible component libraries. We don't want that.[/b]

So, I would like to request the Mojarra team to upgrade the implementation a little bit -- to run scripts even for INPUT elements.


P.S. I understand, that if the component's implementation is wrapped inside a container element such as DIV or SPAN, the scripts will be executed. But that requires additional (arcane) knowledge. The idea of the JSF implementation is to "just work". It would be much better, if ALL scripts get executed, regardless of what element they are attached to.

(For further info, see my post on the PrimeFaces forum: http://primefaces.prime.com.tr/forum/viewtopic.php?f=3&t=1312&start=10#p7712)
[Message sent by forum member 'vesuvius' (vesuvius_prime_at_hotmail.com)]

http://forums.java.net/jive/thread.jspa?messageID=390644