2009/11/17 Jim Driscoll <span dir="ltr"><<a href="mailto:Jim.Driscoll@sun.com">Jim.Driscoll@sun.com</a>></span><br><div class="gmail_quote"><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
Sorry be be hard-nosed about this, but...<br>
<br>
This isn't really the place to discuss implementation bugs. Rather, if you have specific concerns about the specification, they should be discussed here. That would typically imply that you would refer to an area of the spec when reporting such bugs.<br>
<br>
We're going to have to start enforcing this rule vigorously if we open this list up more to the public, or else we're going to end up getting swamped in "my component doesn't work" emails, and we'll be unable to get anything else done.<br>
</blockquote><div><br><br>You are correct. My apologies.<br><br><br>david<br> </div><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
<br>
That said, your mail brings up a few gaps in the specification, though you don't refer explicitly to the spec. <br></blockquote><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
<br>
Spec bug 1: There is no defined way to specify an arbitrary method to be called server-side on the execution of a jsf.ajax.request function call.<br>
<br>
This is an oversight in the spec, and it should be addressed for 2.1. In the meantime, you can get *almost* equivalent functionality by using a valueChange listener or an action listener in most cases.<br>
<br>
I've filed spec bug 672 to track this issue. This isn't the first time it's come up, but no one bothered to file it last time, apparently - I thought they had.<br>
<br>
<a href="https://javaserverfaces-spec-public.dev.java.net/issues/show_bugcgi?id=672" target="_blank">https://javaserverfaces-spec-public.dev.java.net/issues/show_bug.cgi?id=672</a><br>
<br>
The workaround you tried, adding the listener then calling the request manually, is just that, a workaround, that had never (that I know of) been tried before we released - so it's not surprising to me that it ran into trouble of various sorts. The behavior you found is probably a bug (but possibly not, I'll have to code trace and look at the spec to be sure), please file it against the implementation, and I'll take a look when I have time. Setting the javax.faces.behavior.event parameter to action should happen automatically for buttons - but that's an implementation specific detail at this point - it's not in the spec. And as such, you *really* shouldn't be talking about it in a book about standard JSF practice.<br>
<br>
I'd much rather you encourage end users to use action listeners and valuechange listeners, for which I have a number of demos. The functionality is roughly equivalent, though they'll still function if JavaScript is also disabled in the page - which I'd regard as a feature, rather than a drawback (and which is why it's probably better practice to do it that way for most uses).<br>
<br>
Where this turns a little silly, of course, is in the case that you're trying - a disconnected request that attempts to run an arbitrary method. But even that has a simple (if inelegant) workaround - a hidden button.<br>
<br>
I wrote a demo that does poll, and is in the Mojarra samples - did you look at it? It uses that hidden button mechanism to get around the same problem you're encountering. It doesn't cancel, but that's trivial to add.<br>
<br>
Doing it your proposed way, by registering an ajax listener, is also fraught for another reason that I don't think you've yet considered: event names. The javax.faces.behavior.event parameter is not part of the spec. So, if you want to trigger it for something besides "action", you can't. Even when (if) I do fix the above bug.<br>
<br>
And, as I said, allowing arbitrary method calls from jsf.ajax.request is something that really should be in 2.1. And it will probably mean setting the "unintuitive" javax.faces.behavior.event parameter, unless someone can come up with a more elegant way. Hopefully, someone will.<br>
<br>
Your second reported bug is almost certainly an implementation bug. Please file it - as I said, this isn't the place to discuss implementation bugs. We often discuss implementation bugs on <a href="mailto:webtier@glassfish.dev.java.net" target="_blank">webtier@glassfish.dev.java.net</a>, if you'd like to subscribe. I'm running a little behind on there (we're doing a release right now), but we have a pretty good answer rate.<br>
<br>
Again, I'm sorry to come off as not caring about this - I care very much about every bug we find. But I know from past experience that if we let the discussion deviate from the charter of this list, It Won't End Well.<br>
<br>
Jim<br>
<br>
P.S. Ken - the suggestion to cancel an in process request is one that I used to favor as well, but that brings up data integrity and consistency issues that are better handled server side. So I'm now reluctantly against allowing that (at least the simple case - though canceling a request that hasn't yet begun would be something that I'd like to support). But still, if you would like to see this in 2.1, please file a spec feature request.<div class="im">
<br>
<br>
On 11/17/09 8:21 AM, David Geary wrote:<br>
</div><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;"><div class="im">
I meant to send this to the open mailing list in the first place, so I'm<br>
forwarding my original message and Ken's response.<br>
<br>
---------- Forwarded message ----------<br></div><div class="im">
From: *Ken Paulsen* <<a href="mailto:Ken.Paulsen@sun.com" target="_blank">Ken.Paulsen@sun.com</a> <mailto:<a href="mailto:Ken.Paulsen@sun.com" target="_blank">Ken.Paulsen@sun.com</a>>><br>
Date: 2009/11/16<br>
Subject: Re: [jsr-314-open] [jsr-314-eg] Ajax bugs?<br></div><div><div></div><div class="h5">
To: <a href="mailto:jsr-314-eg@jcp.org" target="_blank">jsr-314-eg@jcp.org</a> <mailto:<a href="mailto:jsr-314-eg@jcp.org" target="_blank">jsr-314-eg@jcp.org</a>><br>
Cc: Cay Horstmann <<a href="mailto:cay@horstmann.com" target="_blank">cay@horstmann.com</a> <mailto:<a href="mailto:cay@horstmann.com" target="_blank">cay@horstmann.com</a>>><br>
<br>
<br>
<br>
Below are some of my experiences... may be helpful, may not be. :)<br>
<br>
Ken<br>
<br>
<br>
David Geary wrote:<br>
</div></div><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;"><div><div></div><div class="h5">
Sorry for the long email, but it should be easy to grok.<br>
<br>
I'm trying to get a simple Ajax polling example working, and I'm not<br>
having much luck. I think I'm running across two Ajax bugs in mojarra.<br>
Here's my markup:<br>
<br>
<h:form prependId="false"><br>
<br>
<h:commandButton value="Start polling" id="startPollingButton"<br>
onclick="startPolling(this, event,<br>
'pollOutput')"<br>
action="#{user.incrementPollIndex}"><br>
<br>
<f:ajax listener="#{user.ajaxListener}"/><br>
<br>
</h:commandButton><br>
<br>
<br/><br>
<br>
<h:outputText value="pollOutput is: #{user.pollIndex}" id="pollOutput"/><br>
<br>
<br/><br>
<br>
<h:commandButton id="stopPollingButton" value="Stop polling"<br>
action="#{user.stopPolling}"/><br>
<br>
</h:form><br>
<br>
I have two buttons, one to start polling, and the other to stop. I<br>
also have an output that displays a backing bean property<br>
(#{user.pollIndex}). When you click the start button, it calls my<br>
startPolling JavaScript function. That function starts a timer which<br>
repeatedly calls jsf.ajax.request():<br>
<br>
<script type="text/javascript"><br>
function startPolling(component, event, renderComponents) {<br>
var pollFunction = function poll() {<br></div></div>
jsf.ajax.request(<a href="http://component.id" target="_blank">component.id</a> <<a href="http://component.id" target="_blank">http://component.id</a>>,<div class="im"><br>
event, { render: renderComponents } )<br>
}<br>
var timer = window.setInterval(pollFunction, 200);<br>
}<br>
</script><br>
<br>
Bug #1: Ajax listener is not invoked when I call jsf.ajax.request()<br>
manually.<br>
</div></blockquote><div class="im">
I ran into the same issue when trying to do something similar recently.<br>
This should make what you have work:<br>
<br>
function startPolling(component, event, renderComponents) {<br>
var props = {<br></div>
execute: <a href="http://component.id" target="_blank">component.id</a> <<a href="http://component.id" target="_blank">http://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">http://component.id</a>>] = <a href="http://component.id" target="_blank">component.id</a><br>
<<a href="http://component.id" target="_blank">http://component.id</a>>;<div class="im"><br>
var pollFunction = function poll() {<br>
jsf.ajax.request(component, event, props);<br>
}<br>
window.setInterval(pollFunction, 200);<br>
}<br>
<br></div>
I am not sure if the <a href="http://component.id" target="_blank">component.id</a> <<a href="http://component.id" target="_blank">http://component.id</a>> = <a href="http://component.id" target="_blank">component.id</a><br>
<<a href="http://component.id" target="_blank">http://component.id</a>> in "props" is necessary, it is for the button<div class="im"><br>
component that I am using and I haven't spent the time to find out why<br>
or if it is also needed for h:* components. I think the execute one is<br>
needed also. You can also use '@all' to execute everything (or render<br>
everything). Also, it's better to pass in 'component' instead of<br></div>
'<a href="http://component.id" target="_blank">component.id</a> <<a href="http://component.id" target="_blank">http://component.id</a>>' for the src argument since the<div class="im"><br>
implementation just searches for 'component' again if you don't pass it<br>
in directly.<br>
<br>
One thing you should be aware of is that if your requests do not<br>
complete in 2 seconds, they'll start queuing up. There should be a way<br>
to terminate previously queued requests that have not yet fired... but I<br>
don't think there is a public way to do this. Please correct me if I'm<br>
wrong.<br>
<br>
<br>
<br>
<blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
Everytime I call jsf.ajax.request() in poll(), the button's action<br>
gets called, as I expect. However, the Ajax listener associated with<br>
the button is only called when I actually click the button, and not<br>
when the poll() function is invoked. I expect the Ajax listener, like<br>
the button's action, to be invoked everytime I call<br>
jsf.ajax.request(). That seems like a reasonable expectation to me.<br>
</blockquote>
I think this is expected b/c you are not "executing" the button in your<br>
Ajax request. Hmm... after looking at the jsf.js code, it does default<br></div>
to <a href="http://component.id" target="_blank">component.id</a> <<a href="http://component.id" target="_blank">http://component.id</a>> (and <a href="http://component.name" target="_blank">component.name</a><br>
<<a href="http://component.name" target="_blank">http://component.name</a>> for some reason). So it should work as you<div class="im"><br>
expect... perhaps I worked around this bug when I shouldn't have had<br>
to... I'm confused now. :)<br>
<br>
</div><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;"><div class="im">
<br>
After rummaging around in the RI code, I found that I could get<br>
mojarra to call the Ajax listener everytime I call poll() if I change<br>
the call above to jsf.ajax.request() to this:<br>
<br></div>
jsf.ajax.request(<a href="http://component.id" target="_blank">component.id</a> <<a href="http://component.id" target="_blank">http://component.id</a>>,<div><div></div><div class="h5"><br>
event, { render: renderComponents, 'javax.faces.behavior.event':<br>
'action' } )<br>
<br>
Ugh. That's not very intuitive. Why do I have to do that? I expect the<br>
Ajax listener to be called without having to resort to such slight of<br>
hand.<br>
<br>
<br>
Bug #2: Removing components from the tree in an Ajax listener does not<br>
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<br>
listener I tried two things: 1. set the rendered attribute of the<br>
output to false. 2. remove the output component from it's parent's<br>
list of components. Neither works. In both cases, the output remains<br>
in the page until I do a full page refresh, and then it disappears.<br>
The output no longer updates after it's removed (or it's rendered<br>
attribute is set to false), but it's still in the page. Note that I am<br>
specifying that the output component is rendered after the Ajax call.<br>
<br>
If I manually remove a component, or set it's rendered attribute to<br>
true, during an Ajax call, I expect that component to disappear when<br>
the Ajax call returns, provided of course, that it's one of the<br>
components to be rendered when the Ajax call returns.<br>
</div></div></blockquote><div><div></div><div class="h5">
I ran into this also. However, if you think about it... this one makes<br>
sense. You tell it to go through the render phase for a component that<br>
says don't produce any output... so that's what it does (render==false<br>
case). And for the render == invalid id case, the current behavior does<br>
nothing. However, it probably should be smarter and return a "delete"<br>
xml element to handle this...<br>
<br>
To work-a-round this one, we added a hack that detected an empty Ajax<br>
response and manipulated the HTML DOM in our own JS... fortunately we<br>
only expected 1 object to be upated so this worked for us. Not a good<br>
work-a-round. We possibly could have changed our server-side logic to<br>
change the 'style' of the component to 'display:none;' instead...<br>
anyway, I agree with you on this issue.<br>
<br>
Ken<br>
<br>
<blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
<br>
Are these bugs, or are my expectations out of line?<br>
<br>
Thanks,<br>
<br>
<br>
david<br>
<br>
<br>
<br>
<br>
</blockquote>
<br>
</div></div></blockquote>
</blockquote></div><br>