[jsr-314-open] Fwd: [jsr-314-eg] Ajax bugs?

David Geary clarity.training at gmail.com
Tue Nov 17 11:21:51 EST 2009


I meant to send this to the open mailing list in the first place, so I'm
forwarding my original message and Ken's response.

---------- Forwarded message ----------
From: Ken Paulsen <Ken.Paulsen at sun.com>
Date: 2009/11/16
Subject: Re: [jsr-314-open] [jsr-314-eg] Ajax bugs?
To: jsr-314-eg at jcp.org
Cc: Cay Horstmann <cay at horstmann.com>



Below are some of my experiences... may be helpful, may not be. :)

Ken


David Geary wrote:

Sorry for the long email, but it should be easy to grok.

I'm trying to get a simple Ajax polling example working, and I'm not having
much luck. I think I'm running across two Ajax bugs in mojarra. Here's my
markup:

          <h:form prependId="false">

            <h:commandButton value="Start polling" id="startPollingButton"
                           onclick="startPolling(this, event, 'pollOutput')"

                            action="#{user.incrementPollIndex}">

              <f:ajax listener="#{user.ajaxListener}"/>

            </h:commandButton>

            <br/>

            <h:outputText value="pollOutput is: #{user.pollIndex}"
id="pollOutput"/>

            <br/>

            <h:commandButton id="stopPollingButton" value="Stop polling"
action="#{user.stopPolling}"/>

          </h:form>

I have two buttons, one to start polling, and the other to stop. I also have
an output that displays a backing bean property (#{user.pollIndex}). When
you click the start button, it calls my startPolling JavaScript function.
That function starts a timer which repeatedly calls jsf.ajax.request():

      <script type="text/javascript">
        function startPolling(component, event, renderComponents) {
           var pollFunction = function poll() {
                jsf.ajax.request(component.id, event, { render:
renderComponents } )
            }
            var timer = window.setInterval(pollFunction, 200);
        }
      </script>

Bug #1: Ajax listener is not invoked when I call jsf.ajax.request()
manually.

I ran into the same issue when trying to do something similar recently.
This should make what you have work:

    function startPolling(component, event, renderComponents) {
        var props = {
            execute: component.id;
            render: renderComponents;
            }
        props[component.id] = component.id;
        var pollFunction = function poll() {
            jsf.ajax.request(component, event, props);
        }
        window.setInterval(pollFunction, 200);
    }

I am not sure if the component.id = component.id in "props" is necessary, it
is for the button component that I am using and I haven't spent the time to
find out why or if it is also needed for h:* components.  I think the
execute one is needed also.  You can also use '@all' to execute everything
(or render everything).  Also, it's better to pass in 'component' instead of
'component.id' for the src argument since the implementation just searches
for 'component' again if you don't pass it in directly.

One thing you should be aware of is that if your requests do not complete in
2 seconds, they'll start queuing up.  There should be a way to terminate
previously queued requests that have not yet fired... but I don't think
there is a public way to do this.  Please correct me if I'm wrong.



Everytime I call jsf.ajax.request() in poll(), the button's action gets
called, as I expect. However, the Ajax listener associated with the button
is only called when I actually click the button, and not when the poll()
function is invoked. I expect the Ajax listener, like the button's action,
to be invoked everytime I call jsf.ajax.request(). That seems like a
reasonable expectation to me.

I think this is expected b/c you are not "executing" the button in your Ajax
request.  Hmm... after looking at the jsf.js code, it does default to
component.id (and component.name for some reason).  So it should work as you
expect... perhaps I worked around this bug when I shouldn't have had to...
I'm confused now. :)


After rummaging around in the RI code, I found that I could get mojarra to
call the Ajax listener everytime I call poll() if I change the call above to
jsf.ajax.request() to this:

             jsf.ajax.request(component.id, event, { render:
renderComponents, 'javax.faces.behavior.event': 'action' } )

Ugh. That's not very intuitive. Why do I have to do that? I expect the Ajax
listener to be called without having to resort to such slight of hand.


Bug #2: Removing components from the tree in an Ajax listener does not
remove the component from the page when the Ajax call returns.

When polling is complete, I want to remove the output, so in the Ajax
listener I tried two things: 1. set the rendered attribute of the output to
false. 2. remove the output component from it's parent's list of components.
Neither works. In both cases, the output remains in the page until I do a
full page refresh, and then it disappears. The output no longer updates
after it's removed (or it's rendered attribute is set to false), but it's
still in the page. Note that I am specifying that the output component is
rendered after the Ajax call.

If I manually remove a component, or set it's rendered attribute to true,
during an Ajax call, I expect that component to disappear when the Ajax call
returns, provided of course, that it's one of the components to be rendered
when the Ajax call returns.

I ran into this also.  However, if you think about it... this one makes
sense.  You tell it to go through the render phase for a component that says
don't produce any output... so that's what it does (render==false case).
And for the render == invalid id case, the current behavior does nothing.
However, it probably should be smarter and return a "delete" xml element to
handle this...

To work-a-round this one, we added a hack that detected an empty Ajax
response and manipulated the HTML DOM in our own JS... fortunately we only
expected 1 object to be upated so this worked for us.  Not a good
work-a-round.  We possibly could have changed our server-side logic to
change the 'style' of the component to 'display:none;' instead... anyway, I
agree with you on this issue.

Ken


Are these bugs, or are my expectations out of line?

Thanks,


david
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.jboss.org/pipermail/jsr-314-open-mirror/attachments/20091117/86e029ce/attachment.html 


More information about the jsr-314-open-mirror mailing list