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

David Geary clarity.training at gmail.com
Thu Nov 19 12:12:04 EST 2009


2009/11/17 Jim Driscoll <Jim.Driscoll at sun.com>

> Sorry be be hard-nosed about this, but...
>
> 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.
>
> 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.
>


You are correct. My apologies.


david


>
> That said, your mail brings up a few gaps in the specification, though you
> don't refer explicitly to the spec.
>

> 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.
>
> 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.
>
> 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.
>
> https://javaserverfaces-spec-public.dev.java.net/issues/show_bug.cgi?id=672
>
> 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.
>
> 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).
>
> 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.
>
> 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.
>
> 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.
>
> 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.
>
> 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 webtier at glassfish.dev.java.net,
> 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.
>
> 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.
>
> Jim
>
> 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.
>
>
> On 11/17/09 8:21 AM, David Geary wrote:
>
>> 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 <mailto:Ken.Paulsen at sun.com>>
>> Date: 2009/11/16
>> Subject: Re: [jsr-314-eg] Ajax bugs?
>> To: jsr-314-eg at jcp.org <mailto:jsr-314-eg at jcp.org>
>> Cc: Cay Horstmann <cay at horstmann.com <mailto: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 <http://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 <http://component.id>;
>>             render: renderComponents;
>>             }
>>         props[component.id <http://component.id>] = component.id
>> <http://component.id>;
>>
>>         var pollFunction = function poll() {
>>             jsf.ajax.request(component, event, props);
>>         }
>>         window.setInterval(pollFunction, 200);
>>     }
>>
>> I am not sure if the component.id <http://component.id> = component.id
>> <http://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 <http://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 <http://component.id> (and component.name
>> <http://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 <http://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/20091119/54dd85bf/attachment.html 


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