I meant to send this to the open mailing list in the first place, so I&#39;m forwarding my original message and Ken&#39;s response.<br><br><div class="gmail_quote">---------- Forwarded message ----------<br>From: <b class="gmail_sendername">Ken Paulsen</b> <span dir="ltr">&lt;<a href="mailto:Ken.Paulsen@sun.com">Ken.Paulsen@sun.com</a>&gt;</span><br>
Date: 2009/11/16<br>Subject: Re: [jsr-314-eg] Ajax bugs?<br>To: <a href="mailto:jsr-314-eg@jcp.org">jsr-314-eg@jcp.org</a><br>Cc: Cay Horstmann &lt;<a href="mailto:cay@horstmann.com">cay@horstmann.com</a>&gt;<br><br><br>


  
  

<div bgcolor="#ffffff" text="#000000">
<br>
Below are some of my experiences... may be helpful, may not be. :)<br>
<br>
Ken<div class="im"><br>
<br>
David Geary wrote:
<blockquote type="cite">Sorry for the long email, but it should be easy to grok.<br>
  <br>
I&#39;m trying to get a simple Ajax polling example working, and I&#39;m not
having much luck. I think I&#39;m running across two Ajax bugs in mojarra.
Here&#39;s my markup:<br>
  <br>
          &lt;h:form prependId=&quot;false&quot;&gt;<br>
  <br>
            &lt;h:commandButton value=&quot;Start polling&quot;
id=&quot;startPollingButton&quot;<br>
                           onclick=&quot;startPolling(this, event,
&#39;pollOutput&#39;)&quot; <br>
                            action=&quot;#{user.incrementPollIndex}&quot;&gt;<br>
  <br>
              &lt;f:ajax listener=&quot;#{user.ajaxListener}&quot;/&gt;<br>
  <br>
            &lt;/h:commandButton&gt;<br>
          <br>
            &lt;br/&gt;<br>
            <br>
            &lt;h:outputText value=&quot;pollOutput is: #{user.pollIndex}&quot;
id=&quot;pollOutput&quot;/&gt;<br>
  <br>
            &lt;br/&gt;<br>
  <br>
            &lt;h:commandButton id=&quot;stopPollingButton&quot; value=&quot;Stop
polling&quot; action=&quot;#{user.stopPolling}&quot;/&gt;<br>
  <br>
          &lt;/h:form&gt;<br>
  <br>
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():<br>
  <br>
      &lt;script type=&quot;text/javascript&quot;&gt;<br>
        function startPolling(component, event, renderComponents) {<br>
           var pollFunction = function poll() {<br>
                jsf.ajax.request(<a href="http://component.id" target="_blank">component.id</a>, event, { render:
renderComponents } )<br>
            }<br>
            var timer = window.setInterval(pollFunction, 200);<br>
        }<br>
      &lt;/script&gt;<br>
  <br>
Bug #1: Ajax listener is not invoked when I call jsf.ajax.request()
manually.<br>
</blockquote></div>
I ran into the same issue when trying to do something similar
recently.  This should make what you have work:<br>
<br>
<tt><div class="im">    function startPolling(component, event, renderComponents) {<br></div>
        var props = {<br>
            execute: <a href="http://component.id" target="_blank">component.id</a>;<br>
            render: renderComponents;<br>
            }<br>
        props[<a href="http://component.id" target="_blank">component.id</a>] = <a href="http://component.id" target="_blank">component.id</a>;<br>
</tt><tt>        var pollFunction = function poll() {<br>
            jsf.ajax.request(component, event, props);<br>
        }<br>
        window.setInterval(pollFunction, 200);<br>
</tt><tt>    }<br>
    <br>
</tt>I am not sure if the <a href="http://component.id" target="_blank">component.id</a> = <a href="http://component.id" target="_blank">component.id</a> in &quot;props&quot; is
necessary, it is for the button component that I am using and I haven&#39;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
&#39;@all&#39; to execute everything (or render everything).  Also, it&#39;s better
to pass in &#39;component&#39; instead of &#39;<a href="http://component.id" target="_blank">component.id</a>&#39; for the src argument
since the implementation just searches for &#39;component&#39; again if you
don&#39;t pass it in directly.<br>
<br>
One thing you should be aware of is that if your requests do not
complete in 2 seconds, they&#39;ll start queuing up.  There should be a way
to terminate previously queued requests that have not yet fired... but
I don&#39;t think there is a public way to do this.  Please correct me if
I&#39;m wrong.<div class="im"><br>
<br>
<br>
<blockquote type="cite">Everytime I call jsf.ajax.request() in poll(), the
button&#39;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&#39;s action, to be invoked everytime I call
jsf.ajax.request(). That seems like a reasonable expectation to me.<br>
</blockquote></div>
I think this is expected b/c you are not &quot;executing&quot; the button in your
Ajax request.  Hmm... after looking at the jsf.js code, it does default
to <a href="http://component.id" target="_blank">component.id</a> (and <a href="http://component.name" target="_blank">component.name</a> for some reason).  So it should
work as you expect... perhaps I worked around this bug when I shouldn&#39;t
have had to... I&#39;m confused now. :)<div class="im"><br>
<blockquote type="cite"><br>
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:<br>
  <br>
             jsf.ajax.request(<a href="http://component.id" target="_blank">component.id</a>, event, { render:
renderComponents, &#39;javax.faces.behavior.event&#39;: &#39;action&#39; } )<br>
  <br>
Ugh. That&#39;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.<br>
  <br>
  <br>
Bug #2: Removing components from the tree in an Ajax listener does not
remove the component from the page when the Ajax call returns.<br>
  <br>
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&#39;s parent&#39;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&#39;s removed (or it&#39;s rendered attribute is set
to false), but it&#39;s still in the page. Note that I am specifying that
the output component is rendered after the Ajax call.<br>
  <br>
If I manually remove a component, or set it&#39;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&#39;s one of the
components to be rendered when the Ajax call returns.<br>
</blockquote></div>
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&#39;t produce any output... so that&#39;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
&quot;delete&quot; xml element to handle this...<br>
<br>
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 &#39;style&#39; of the component to &#39;display:none;&#39; instead...
anyway, I agree with you on this issue.<br><font color="#888888">
<br>
Ken</font><div class="im"><br>
<blockquote type="cite"><br>
Are these bugs, or are my expectations out of line?<br>
  <br>
Thanks,<br>
  <br>
  <br>
david<br>
  <br>
  <br>
  <br>
  <br>
</blockquote>
</div></div>

</div><br>