jsr372-experts@javaserverfaces-spec-public.java.net

[jsr372-experts] Re: [jsr372-experts mirror] Re: Improvements for ajax update (related to Handling Focus after Ajax update)

From: Leonardo Uribe <leonardo.uribe_at_irian.at>
Date: Thu, 16 Apr 2015 00:51:19 -0500

Hi

KM>> Thanks for the detailed explanation; I like what you're
KM>> proposing for partial updates; you have provided the
KM>> implementation details of the JSON rendering feature
KM>> I mentioned at JavaOne, except without JSON, of
KM>> course (which is fine)

Yes, that's the idea. Just provide some more concrete ideas
about what to do and how.

I just wanted to mention there are two kinds of ajax request:

- Requests that update a single component with no children.
- Requests that update an specified region in the page (for example
render="@form").

I think in the first case, just include UIComponent.encodeAjax(...) is
more than enough. It is a good idea to send JSON instead xml to make
it less verbose.

The second case is a bit hard to get it out. The most difficult case
is what happen with facelet dynamic tags and programmatically added
components (c:if, c:forEach, c:choose, ui:include src="#{...}",
ui:decorate template="#{...}"). For example:

<h:panelGroup id="panelToUpdate">
  <h:inputText value="#{myBean.input"/>
  <c:if test=#{...}>
      <h:outputText value="#{myBean.value"}/>
   </c:if>
</h:panelGroup>

I think a solution to the problem is just put a mark on the parent
component that holds the dynamic section, so the algorithm can be
aware that the content of the component is dynamically generated and
should be updated fully. We have already done things like that in
MyFaces 2.0 (org.apache.myfaces.REFRESH_TRANSIENT_BUILD_ON_PSS_PRESERVE_STATE
mode uses this as a way to identify which sections need to be saved
fully). Programmatically added components contains special markers
that are implementation specific. So, it could be good to add
UIComponent.markRenderDynamic(), UIComponent.isRenderDynamic()

In few words, a good algorithm should be able to:

- Identify when a component renders a "dynamic markup" and doesn't
have an associated id to the dom tree, or
- Identify if it contains some facelets dynamic components or
programmatically added components.

One good use case where this feature could be helpful is <f:ajax
render="@form"/>. Instead send the whole form markup, the algorithm
will select recursively what really needs to be updated, saving render
time and bandwidth.

KM>> I think there should also be a rendering hook for the
KM>> component in JavaScript so it can decide how to
KM>> render itself

It has sense, if you can send something else on the response that is
not html markup, the component should be able to process it on the
client, and JSF should be able to help fill the gap. It is in fact a
mini-lifecycle:

- Send request.
- Receive response.
- Decode response.
- Update DOM tree
- Update ViewState
- Invoke component handler passing the response (JSON or whatever).

I have always thought jsf.ajax.request(...) onevent is very rigid,
because you can't post-process the incoming response (js function
callback).

regards,

Leonardo Uribe

2015-04-15 17:07 GMT-05:00 Leonardo Uribe <leonardo.uribe_at_irian.at>:
> Hi Kito
>
> KM>> I'm not 100% convinced your solution solves the focusing issue,
> though. How would it handle the following panel:
>
> Please note I'm trying not to mix this with the "focus" problem. We
> need a solution for that problem anyway, because the algorithm
> proposed here will not solve the main issue (sometimes there is no
> other choice than a full update).
>
> In that case the panel should be updated fully, because there is no
> "counterpart" in the DOM tree for the embedded html markup.
>
> Let's suppose that we have included UIComponent.encodeAjax(...) (and
> probably Renderer.encodeAjax(...)). The general algorithm should be
> something like this:
>
> - Call UIComponent.isRenderStatelessMarkup() for the panel.
> - If is false, do a full update as usual.
> - If is true, check on each child for isRenderStatelessMarkup().
> - For each "direct" children that does not return stateless
> markup, check UIComponent.isIdRenderedOnMarkup(). If every child that
> does not render stateless markup has an id rendered, invoke
> UIComponent.encodeAjax(...) on each child (even if is stateless
> markup). The result is the union of those invocations is equivalent to
> a full update.
> - Otherwise update fully.
>
> In the panel case, the UILeaf instance holding the EL expression
> #{myBean.value} will return isRenderStatelessMarkup() false and
> isIdRenderedOnMarkup() false, so the panel will be updated fully.
>
> The nice thing is if the component is something complex like a
> datatable, you can override encodeAjax(...) to do the logic in the
> same way the renderer does.
>
> The key point is that with the inclusion of
> UIComponent.encodeAjax(...), we gain more flexibility in the way how
> the view is updated after an ajax operation. I'm proposing here to do
> that and go further, adding a logic that could allow to check which
> pieces of information really needs to be updated.
>
> I have not checked each detail of the algorithm, but I have the
> feeling this is going to work. My only concern is the time spent
> iterating the component tree, so we need to adapt the algorithm to
> ensure linear complexity (maybe a two-step algorithm seems better).
>
> regards,
>
> Leonardo Uribe
>
> 2015-04-15 9:35 GMT-05:00 Kito Mann <kito.mann_at_virtua.com>:
>> Hello Leonardo,
>>
>> Thanks for the detailed explanation; I like what you're proposing for
>> partial updates; you have provided the implementation details of the JSON
>> rendering feature I mentioned at JavaOne, except without JSON, of course
>> (which is fine). In addition, I think there should also be a rendering hook
>> for the component in JavaScript so it can decide how to render itself (this
>> way, the component can decide the attributes refer to something other than
>> specific DOM element attributes).
>>
>> I'm not 100% convinced your solution solves the focusing issue, though. How
>> would it handle the following panel:
>>
>> <h:panelGroup id="panelToUpdate">
>> <h:inputText value="#{myBean.input"/>
>> <h:outputText value="#{myBean.value"}/>
>> #{myBean.value}
>> </h:panelGroup>
>>
>>
>> ___
>>
>> Kito D. Mann | @kito99 | Author, JSF in Action
>> Virtua, Inc. | http://www.virtua.com | JSF/Java EE training and consulting
>> http://www.JSFCentral.com | @jsfcentral
>> +1 203-998-0403
>>
>> * Listen to the Enterprise Java Newscast: http://enterprisejavanews.com
>> * JSFCentral Interviews Podcast:
>> http://www.jsfcentral.com/resources/jsfcentralpodcasts/
>> * Sign up for the JSFCentral Newsletter: http://oi.vresp.com/?fid=ac048d0e17
>>
>> On Tue, Apr 14, 2015 at 9:42 PM, Leonardo Uribe <leonardo.uribe_at_irian.at>
>> wrote:
>>>
>>> Hi
>>>
>>> I would like to point out some details on the JSF spec about how the ajax
>>> update is being done. This is related to the topic "Handling Focus on
>>> Ajax".
>>> My intention is answer the question "why JSF update the whole markup and
>>> not only the affected attributes" and identify the current flaws on the
>>> spec.
>>>
>>> In my opinion this is a REALLY IMPORTANT FIX, and fortunately the solution
>>> can
>>> be done with a bit of effort.
>>>
>>> The problem is all about how a JSF Component is rendered using an ajax
>>> request.
>>> According to JSF 2.2 spec section 13.4.3 Partial View Rendering, it
>>> says something
>>> like this:
>>>
>>> "... The UIViewRoot getRendersChildren and encodeChildren methods must
>>> determine
>>> if the request is an Ajax request using the FacesContext.isAjaxRequest()
>>> method.
>>> If PartialViewContext.isAjaxRequest() returns true, then the
>>> getRendersChildren
>>> method must return true and the encodeChildren method must perform partial
>>> rendering using the PartialViewContext.processPartial implementation ..."
>>>
>>> This is what it says on PartialViewContext.processPartial(...) javadoc:
>>>
>>> "... Perform lifecycle processing on components during the indicated
>>> phaseId.
>>> Only those components with identifiers existing in the Collection returned
>>> from
>>> getExecuteIds() and getRenderIds() will be processed. ..."
>>>
>>> In few words, PartialViewContext.processPartial(RENDER_RESPONSE_PHASE)
>>> method
>>> is the one responsible of call encodeXXX methods.
>>>
>>> The problem can be seen when you take a look at how the default algorithm
>>> for
>>> PartialViewContext.processPartial(...) really works. I'll describe the
>>> steps
>>> done by this algorithm by default in MyFaces (only what's relevant of
>>> course):
>>>
>>> - Get PartialResponseWriter
>>> - Call writer.startDocument() and set id attribute
>>> - If isRenderAll() true then
>>> - Call writer.startUpdate()
>>> - Call component.encodeAll() for every children of UIViewRoot instance
>>> - Call writer.endUpdate()
>>> - Otherwise for each component in renderIds:
>>> - Call writer.startUpdate()
>>> - Call component.encodeAll()
>>> - Call writer.endUpdate()
>>> - Call writer.endDocument()
>>>
>>> Now, let's suppose you have a component and you know that the only thing
>>> that
>>> changes between ajax request is the attributes attached with
>>> ValueExpression
>>> instances. In
>>>
>>> <h:inputText value="#{myBean.value}">
>>> <f:ajax ...>
>>> </h:inputText>
>>>
>>> HTML Markup
>>>
>>> <input id="j_id_23" type="text" value="..."/>
>>>
>>> Only changes "value" attribute, right?.
>>>
>>> How to do it with the current plumbing? If you take a look at the xsd of
>>> web-partialresponse, you can see this is a possible response:
>>>
>>> <partial-response id="j_id_0">
>>> <changes>
>>> <attributes id="j_id_23">
>>> <attribute name="value" value="new value">
>>> </attributes>
>>> <update id="otherCompId"><![CDATA[... HTML Markup ...]]></update>
>>> </changes>
>>> </partial-response>
>>>
>>> The problem is the default algorithm is not flexible enough, because the
>>> component cannot choose the proper command. By default, a call to update
>>> the DOM markup is always done and it is always called encodeAll().
>>>
>>> Third-Party vendors usually override
>>> PartialViewContext.processPartial(...)
>>> to do some extra processing, but on the way, they override existing
>>> behavior
>>> and create incompatibilities between libraries overriding the same lines
>>> of
>>> code.
>>>
>>> The proposal is add a new method in UIComponent called
>>> encodeAjax(FacesContext context, PartialResponseWriter writer) that by
>>> default execute something like this:
>>>
>>> try
>>> {
>>> writer.startUpdate();
>>> this.encodeAll();
>>> } finally {
>>> writer.endUpdate();
>>> }
>>>
>>> In other words, move the code that writes the "update" section to the
>>> component,
>>> to let the component choose how and when should be updated. In that way,
>>> the component can choose between the valid options:
>>>
>>> - update
>>> - insert DOM node
>>> - delete
>>> - attributes
>>> - eval
>>> - extension
>>>
>>> This change will provide a lot of flexibility that currently we just don't
>>> have
>>> "out of the box".
>>>
>>> Let's try something more complex. Suppose this code:
>>>
>>> <div id="myBigAndComplexPanel">
>>> <!-- A big stateless chunk of HTML Markup -->
>>> <input id="j_id_23" type="text" value="..."/>
>>> <!-- Another big fat stateless chunk of HTML Markup -->
>>> </div>
>>>
>>> And I want to update "myBigAndComplexPanel", but I know that the only
>>> thing I
>>> really need is update the input value. How?
>>>
>>> The key point is to know if each component that matters has an id rendered
>>> on
>>> the DOM markup. If the id is not rendered, we can't update the component
>>> individually, because we don't have the reference, and we will be forced
>>> to
>>> update the whole DOM markup for the panel. Suppose the triggering ajax
>>> says this:
>>>
>>> <f:ajax ... render="myBigAndComplexPanel"/>
>>>
>>> The algorithm call UIComponent.encodeAjax(...) for the panel. Inside, the
>>> component can check if is "stateless" or not, and then invoke
>>> UIComponent.encodeAjax for each child component. UILeaf instances (HTML
>>> markup)
>>> will not process anything, unless they contain embedded EL, but the input
>>> component will think the best way to update itself and at the end it will
>>> add the <attributes>...</attributes> block. If we can identify when the
>>> output of a component has an id (UIComponent.isIdRenderedOnMarkup()) or
>>> contains static markup or not (UIComponent.isRenderStatelessMarkup()),
>>> this
>>> strategy will work. Also something like UIComponent.getUpdatedAttributes()
>>> that used the "delta" state or the existence of ValueExpression instances
>>> in
>>> attributes, to get which ones were changes and build the response.
>>>
>>> In summary: "why JSF update the whole markup and not only the affected
>>> attributes". Because "<update>" solves most of the use cases in core JSF.
>>> It can be done, but there are some use cases that are not so simple to do
>>> and requires some work. Anyway the fix for "handling focus" is required.
>>>
>>> regards,
>>>
>>> Leonardo Uribe
>>
>>