[jsr-314-open-mirror] [jsr-314-open] javax.faces.ViewState + ppr case
by Werner Punz
Hello I am asking this because this because I user ran into this issue by
using a dom modifying javascript widget and tried to press it through
jsf.ajax.request.
(aka a typical dialog widget)
The issue is that there is a usecase where you try to execute a ppr within
one form
and then try to render another form.
aka:
<h:form id="form1">
... jsf.ajax.request(this, event, {execute:"form1 form2", render:"form2"});
</h:form>
<h:form id="form2">
</form2>
The main issue here is that after the request a javax.faces.ViewState
element is issued in the ppr cycle. Now the spec says:
If an update element is found in the response with the identifier
javax.faces.ViewState:
<update id="javax.faces.ViewState">
<![CDATA[...]]>
</update>
locate and update the submitting form's javax.faces.ViewState value with the
CDATA contents from the response.
Now this works coherently with a single form usecase because the viewstate
is issued on the submitting element.
The main problem is, both implementations in this special case have another
behavior.
if the form2 is rendered there is no viewstate element in the udate
id="form2" but after that the viewState element is issued,
now however myfaces swallows it entirely for form2 because of this spec
entry, mojarra updates it only if render:"form2"
but if for instance
<h:panelGroup id="outerFormGroup">
<h:form id="form2">
</form2>
</h:panelGroup>
and render:"outerFormGroup" then it is swallowed as well.
I assume now following, since the viewState is viewRoot related, should´t we
simply update all form elements over the entire page with the new viewState
content and simply add this field for form elements where the viewState
control is not present?
The other solution would be to update all forms where an execute and rendere
happend or at least a rendere happend inside (or as parent node of the form)
Werner
14 years, 8 months
[jsr-314-open-mirror] [jsr-314-open] javadoc bug f:param "disable" attribute
by Leonardo Uribe
Hi
I found a javadoc bug on f:param facelet tag. It contains an attribute
called "disable" that has the following description:
disablefalsefalsejavax.el.ValueExpression
(*must evaluate to *boolean) RELEASE_PENDING - Also update spec for
bookmarkable URL (don't forget the two sources for include-view-params). -
convey precendence feature using non-normative language vs algorithmic Flag
enabling or disabling the inclusion of the parameter
Does that attribute really exists? How it works? Maybe it was already
detected, but better to mention it.
regards,
Leonardo Uribe
14 years, 8 months
[jsr-314-open-mirror] [jsr-314-open] Fwd: State saving of UIViewParameter
by Matthias Wessendorf
Since MyFaces committer "Jakob Korherr" has only read-access to this
list, I am forwarding this mail.
-Matthias
PS: we use this forwarding "work-around" instead of filing issues
against the spec (for discussions).
---------- Forwarded message ----------
From: Jakob Korherr <jakob.korherr(a)gmail.com>
Date: Thu, Apr 8, 2010 at 2:46 PM
Subject: State saving of UIViewParameter
To: Matthias Wessendorf <mwessendorf(a)gmail.com>
Hi,
Yesterday we received an issue about the state saving of an
UIViewParameter in combination with an AJAX request on the MyFaces
user list (see [1] for details). This opened some questions/problems:
UIViewParameter uses the submittedValue to store its value in the
state for the next postback, because obviously the view parameter
won't be in the request parameter map of the next request (which is
the postback). But because its submittedValue is null after the
conversions and validations, it has to be set again before the state
is generated. To accomplish that, the spec currently states to
override encodeAll() and make the call to setSubmittedValue() there.
In addition, encodeAll() has to be called in UIViewRoot.encodeEnd()
for every UIViewParameter in the view. This works perfectly for normal
requests, but when you are using an AJAX request the state is
generated before UIViewRoot.encodeEnd() is called an thus the
submittedValue for every UIViewParameter is null in the state. This
means that the value of every UIViewParameter will be null in the
following request.
Now the easiest solution to this problem, which I also already
committed to MyFaces trunk (again see [1] for details), is to do
mostly the same as in UIViewRoot.encodeEnd() just also in
PartialViewContext.
processPartial() when the PhaseId is RENDER_RESPONSE before the state
is generated to make it work for AJAX-requests.
However I don't really like this solution, because we have to think of
handling UIViewParameters in a special way every time we change
something on any render mechanism. Why don't we just override
saveState() on UIViewParameter and set the submittedValue there before
the state is saved. This will have the same result, but without the
code in UIViewRoot, PartialViewContext and UIViewParameter.encodeAll()
and without future headaches. I also already uploaded a patch for this
to the MyFaces issue at [1].
The second thing I want to bring up here is an issue I ran into while
testing the first one. Imagine you have a page with a required
UIViewParameter called input. You will get a validation error as long
as you don't access the view with ?input=abc. Now if you do that once,
"abc" will be saved as the submittedValue in the state of the
UIViewParameter for every postback and thus will be available for
every further postback. If you now access the view again with a GET
request (non-postback), but without ?input=abc, you will again get a
validation error. However, if you hit any button or link on the view
to generate another postback to the view, the validation error will be
gone, because UIViewParameter takes the value from before ("abc") out
of the model (managed-bean) and sets it in the state. Thus you haven't
provided it via ?input=abc, but you will now have a value of "abc" for
your UIViewParameter, which seems kinda wrong to me. The solution to
this one is to get the value from the model to set it as the
submittedValue in UIViewParameter only if the current request is a
postback. However I don't know if this really is an error or the
expected behaviour. I personally just think that it is weird.
Many thanks for looking at this!
Regards,
Jakob
[1] https://issues.apache.org/jira/browse/MYFACES-2645
--
Matthias Wessendorf
blog: http://matthiaswessendorf.wordpress.com/
sessions: http://www.slideshare.net/mwessendorf
twitter: http://twitter.com/mwessendorf
14 years, 8 months
[jsr-314-open-mirror] [jsr-314-open] Cannot call UIComponent.getCurrentComponent() from UIComponent.restoreState() or UIComponent.saveState()
by Leonardo Uribe
Hi
The javadoc of UIComponent.processRestoreState() says this:
*"....Perform the component tree processing required by the Restore View
phase of the request processing lifecycle for all facets of this component,
all children of this component, and this component itself, as follows.
* Call the restoreState() method of this component.
* Call pushComponentToEL(javax.faces.context.FacesContext,
javax.faces.component.UIComponent).
* Call the processRestoreState() method of all facets and children of
this UIComponent in the order determined by a call to
getFacetsAndChildren(). After returning from the processRestoreState()
method on a child or facet, call
popComponentFromEL(javax.faces.context.FacesContext)..."*
The javadoc of UIComponent.processSaveState() says this:
*".....Perform the component tree processing required by the state saving
portion of the Render Response phase of the request processing lifecycle for
all facets of this component, all children of this component, and this
component itself, as follows.
* consult the transient property of this component. If true, just return
null.
* Call pushComponentToEL(javax.faces.context.FacesContext,
javax.faces.component.UIComponent).
* Call the processSaveState() method of all facets and children of this
UIComponent in the order determined by a call to getFacetsAndChildren(),
skipping children and facets that are transient. Ensure that
popComponentFromEL(javax.faces.context.FacesContext) is called correctly
after each child or facet.
* Call the saveState() method of this component.
* Encapsulate the child state and your state into a Serializable Object
and return it....."*
The question is: Doesn't suppose that when you call
UIComponent.getCurrentComponent() inside UIComponent.restoreState(), it
returns the "current component"?. There is one case when we need to do this
call and is on the wrapper used by UIComponent.subscribeToEvent(). The
javadoc of this method says this:
*"....Install the listener instance referenced by argument componentListener
as a listener for events of type eventClass originating from this specific
instance of UIComponent. The default implementation creates an inner
SystemEventListener instance that wraps argument componentListener as the
listener argument. This inner class must call through to the argument
componentListener in its implementation of
SystemEventListener.processEvent(javax.faces.event.SystemEvent) and its
implementation of SystemEventListener.isListenerForSource(java.lang.Object)
must return true if the instance class of this UIComponent is assignable
from the argument to isListenerForSource...."
*
Both myfaces and mojarra has the wrapper described by the javadoc, and that
one is responsible to save/restore the system event listeners attached. To
restore the "component" reference required, both implementations call
UIComponent.getCurrentComponent() and both call processEvent but for the
parent!.
It is obviously a bug (I don't see a valid reason why do the algorithm
described), if you look other methods like processDecodes, you see the right
pattern:
* * If the rendered property of this UIComponent is false, skip further
processing.
* Call pushComponentToEL(javax.faces.context.FacesContext,
javax.faces.component.UIComponent).
* Call the processDecodes() method of all facets and children of this
UIComponent, in the order determined by a call to getFacetsAndChildren().
* Call the decode() method of this component.
* Call popComponentFromEL(javax.faces.context.FacesContext) from inside
of a finally block, just before returning.
* If a RuntimeException is thrown during decode processing, call
FacesContext.renderResponse() and re-throw the exception.
*
I'll change myfaces algorithm to look like processDecodes(). But anyway, it
is necessary to do the proper change on mojarra and on spec javadoc.
regards,
Leonardo Uribe
14 years, 8 months
[jsr-314-open-mirror] [jsr-314-open] status of <composite:clientBehavior> (was Re: "for" attribute for <f:ajax>)
by David Geary
There is a <composite:clientBehavior> tag in the 2.0 version of JSF that
comes with GlassFish, and it appears to work as advertised by Alexandr and
Andy below.
But, as Alexandr points out, it’s not documented in the PDL docs, nor could
I find any mention of it in the spec (or Ed’s book, either).
This is a vital tag that lets page authors attach ajax functionality to
components within composite components. I see no reason why it should not be
documented.
Does anyone know why this tag was not documented in the first place, or what
the plans are for its future? Anyone know if it works with MyFaces 2.0?
If there’s not a compelling reason for blacklisting it from the docs, can we
document it?
Thanks,
david
2009/5/26 Alexandr Smirnov <asmirnov(a)exadel.com>
> Sure, the composite client event tags are not included in the PDL doc.
> There is one <composite:clientBehavior> tag with attributes:
> 'name' -
> the virtual event name that composite component has.
> 'default' "true/false" defines the default event that is enclosed
> <f:ajax> tag serves if 'event' attribute was omited.
> 'event' - the real event name for target component.
> 'targets' - space-delimited list of component id's for which composite
> component behavior or <f:ajax> tag will be redirected.
>
> The model with 'for' attribute was the first implementation but it was
> replaced wit 'virtual' event model.
>
> Andy Schwartz wrote:
> > David -
> >
> > David Geary wrote On 5/24/2009 5:55 PM ET:
> >> For JSF 2, we added a "for" attribute to f:actionListener,
> >> f:converter, etc., but we don't have a "for" attribute for <f:ajax>.
> >> AFAICT, that means that although you can attach listeners, validators,
> >> converters, etc. to a component contained in a composite component,
> >> you cannot attach Ajax functionality.
> >>
> >> Why is that? Is it an oversight, or is there some compelling technical
> >> reason to disallow adding Ajax behavior to components contained in
> >> composites?
> >
> > We definitely intended to support this, though instead of exposing a
> > "for" attribute on <f:ajax>, we wanted to leverage the fact that
> > behaviors already have a targeting mechanism in the "event" name. The
> > idea was that a composite component would, like any other
> > ClientBehaviorHolder, expose a set of logical event names that behaviors
> > can be attached to. So, for example, assuming a composite component
> > included "OK" and "Cancel" buttons and wanted to allow the user to
> > attach action behaviors to these, the composite component might surface
> > "okAction" and "cancelAction" event names, allowing the page author to
> do:
> >
> > <foo:someComposite>
> > <f:ajax event="okAction"/>
> > <f:ajax event="cancelAction"/>
> > </foo:someComposite>
> >
> > I know that Alexander did the implementation work to get this up and
> > running. However, I do not see any pdldoc for the composite tag that
> > the composite component author uses to specify the supported client
> > behavior event names (composite:clientBehavior I believe).
> >
> > Alex, Roger -
> >
> > Did this make it into 2.0?
> >
> > Andy
> >
> >>
> >> Thanks,
> >>
> >>
> >> david
>
14 years, 8 months
[jsr-314-open-mirror] [jsr-314-open] question regarding ajax update cycle
by Werner Punz
Hello everyone, I ran into an issue regarding the update, which is closely
related to a behavior jsf2 exposes regarding component rendering
in the update cycle.
The main issue is following: If we have a component which we trigger with
following code:
<myComp:javascriptTestComponent
id="myTestComponent"></grv:javascriptTestComponent>
<a href="#" name="mego3"
onclick="jsf.ajax.request(this,event,{execute:'myTestComponent',
render:'myTestComponent'}); return false;">submit
me</a>
and the component itself renders following in its renderer:
ResponseWriter writer = context.getResponseWriter();
writer.startElement(DIV, component);
writer.writeAttribute(ID,component.getClientId(context), null );
writer.write("hello world"+Math.random());
writer.endElement(DIV);
writer = context.getResponseWriter();
writer.startElement(DIV, component);
writer.writeAttribute(ID,component.getClientId(context)+":_second",
null );
writer.write("hello world"+Math.random());
writer.endElement(DIV);
the resulting ppr response now looks like following:
<update id="myTestComponent">
<![CDATA[<div id="myTestComponent">hello world0.8619488403376933</div>
<div id="myTestComponent:_second">hello world0.25176272071402683</div>]]>
</update>...
Now the problem is, since the update part of the response is already opened
the component author cannot really influence the response rendering in any
meaningful way (the correct solution would be to issue two update commands
here)
Now the javascript has to react on the client side to resolve that
situation.
Now MyFaces just replaced the original
myTestComponent
with the update code and hence the result was a div wandering down (aka
wrong update)
hello world0.48748236239247755
hello world0.6020541783857698
hello world0.7181842402648805
hello world0.2803064696069696
(after a handful of requests, with the lowest line being the first second
div being dran)
now due to being incorrect a user gave me rightfully a bug issue. I dug
deeper and ran the same example
against Mojarra, now Mojarra does cherry pick the delivered first div and
replaces the original div, and omits the second one.
The Problem is Mojarra just does it for newer browsers, it does the same
just updating the original element with the replacement code
(and hence producing a wandering div) for IE6+7-
My question is, first, how to handle that problem correctly. Secondly, is
this even a problem for us or more one for the component author?
In the end the main problem would not exist if they ajax api could be used
on the component side properly without being enforced already into an update
(or to allow nested updates, inserts within an update)
Werner
14 years, 9 months