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

[jsr372-experts] Re: [jsr372-experts mirror] Re: Re: Re: Re: Re: [JAVASERVERFACES_SPEC_PUBLIC-1423] Dynamic resource loading in ajax requests

From: Bauke Scholtz <balusc_at_gmail.com>
Date: Tue, 26 Jul 2016 05:12:06 +0000

Hi,

Thank you for your thoughts. Definitely valid. I will take those into
account.

How about javax.faces.Resource instead of javax.faces.ViewHead?

Cheers, B

On Tue, Jul 26, 2016, 02:31 Leonardo Uribe <leonardo.uribe_at_irian.at> wrote:

> Hi
>
> BS>> 1. No substantial changes in API/impl are necessary in order to
> discover
> BS>> newly added component resources provided that they are all added via
> BS>> UIViewRoot#addComponentResource().
>
> Yes, it looks good. Good idea to use UIViewRoot#processEvent() and
> PostRestoreStateEvent.
>
> The only thing to notice is the simplification done for a component
> resource
> in order to be added. I resume it in this sentence:
>
> "... If a component resource has "name" and optionally "library" property
> set
> and does not have children and
> ResourceHandler#getRendererTypeForResourceName(
> String resourceName) and getRendererType() is equals to
> 'javax.faces.resource.Script' ..."
>
> What I mean is the way how the simplification is done must be explicit in
> the
> spec. That also means the full algorithm must be somewhere in the javadoc
> or
> in the spec pdf, maybe adding some lines in JSF 2.3 section 13 Ajax
> Integration.
>
> I would like a general solution to the problem, but I think a
> simplification
> for only .js resources is also valid.
>
> BS>> 2. I would like to (re)use the currently unsupported <update
> BS>> id="javax.faces.ViewHead"> in jsf.js to perform adding of new
> component
> BS>> resources.
>
> Unfortunately here there is a problem. This has been already specified in
> the
> javascript documentation of jsf.ajax.response(request, context);
>
> "... If an <update> element is found in the response with the identifier
> javax.faces.ViewRoot:
>
> <update id="javax.faces.ViewRoot">
> <![CDATA[...]]>
> </update>
>
> Update the entire DOM replacing the appropriate head and/or body sections
> with the content from the response. ..."
>
> The hack done in MyFaces works because this part was specified, so I do not
> think it is a good idea to change that meaning. Instead, one way to fix
> the problem is adding the necessary methods to PartialResponseWriter, as
> suggested before. It is not pretty (update facelet-partialresponse .xsd,
> fix PartialResponseWriter, update section 13 ...), but I have not found
> another way to fix it yet.
>
> regards,
>
> Leonardo Uribe
>
>
> 2016-07-22 11:30 GMT-05:00 Bauke Scholtz <balusc_at_gmail.com>:
>
>> Hi,
>>
>> I posted a comment on
>> https://java.net/jira/browse/JAVASERVERFACES_SPEC_PUBLIC-1423 with my
>> new findings and thoughts.
>>
>> In a nutshell:
>>
>> 1. No substantial changes in API/impl are necessary in order to discover
>> newly added component resources provided that they are all added via
>> UIViewRoot#addComponentResource().
>> 2. I would like to (re)use the currently unsupported <update
>> id="javax.faces.ViewHead"> in jsf.js to perform adding of new component
>> resources.
>>
>> Cheers, B
>>
>>
>> On Mon, Jul 4, 2016 at 8:06 PM, Leonardo Uribe <leonardo.uribe_at_irian.at>
>> wrote:
>>
>>> Hi
>>>
>>> BS>> As to "render target", isn't PartialViewContext#getRenderIds()
>>> sufficient
>>> BS>> for the task? This returns a mutable collection of client IDs which
>>> need
>>> BS>> to be updated on current partial request.
>>>
>>> I have been thinking about this for some time to see what's missing from
>>> the
>>> spec perspective, and the answer is no, getRenderIds() is not enough to
>>> do
>>> the job (in my personal opinion).
>>>
>>> The reason is getRenderIds() relies on the fact that it should be a html
>>> tag
>>> with an id rendered on the client markup that can be updated. If there
>>> is
>>> no html tag with id set, an ajax update will not work. Please note
>>> getRenderIds() works for most cases, but for <head> and <body> tags, both
>>> does not allow an id to be set. It is true that there is a solution
>>> updating
>>> the whole content, but the central point is there is a better solution
>>> that
>>> could be done with the changes proposed previously in this thread.
>>>
>>> In summary, the current algorithm for ajax has these weaknesses (sorry if
>>> you found this too repetitive):
>>>
>>> 1. Resource components added as part of a partial update requires to
>>> add some html markup inside a <head> or <body> tag, and both tags does
>>> not have
>>> an id set, and the current API doesn't help to do it without replace
>>> the whole tag.
>>> 2. If a new component is added, there is no html tag we can use to
>>> update it.
>>>
>>> The first case we have already discussed.
>>>
>>> The second one is more theoretical but goes far beyond what we have
>>> discussed.
>>> Anyway, just for clarity sake I'm going to describe it fully and give a
>>> possible solution.
>>>
>>> Think about this fragment:
>>>
>>> <h:panelGroup id="content" layout="block">
>>> <c:if test="#{bean.chooseSomething}">
>>> <h:outputScript name="script2.js"/>
>>> </c:if>
>>> <h:commandButton value="Update" actionListener="#{bean.check}">
>>> <f:ajax />
>>> </h:commandButton>
>>> </h:panelGroup>
>>>
>>> Now imagine that when an ajax request is triggered, the code inside
>>> bean.check() changes chooseSomething from false to true. The lifecycle
>>> looks
>>> like this:
>>>
>>> - Lifecycle Execute (....) invoke bean.check, change chooseSomething to
>>> true.
>>> - Call to vdl.buildView() refresh the whole component tree =>
>>> h:outputScript
>>> added and PostAddToViewEvent is triggered.
>>> - f:ajax requires h:commandButton to be rendered, so a partial update
>>> over the
>>> commandButton is activated.
>>>
>>> What's wrong with this? A new component (h:outputScript) was added on a
>>> partial request. But the component never had the chance to update
>>> itself, so
>>> the script was never updated. Ok, you can replace f:ajax with:
>>>
>>> <f:ajax render="content"/>
>>>
>>> Problem solved, but is all that really necessary? What if
>>> chooseSomething does
>>> not change? why update the content in that case?.
>>>
>>> Please note every component addition triggers a PostAddToViewEvent. It
>>> is
>>> possible to use that event to detect the change. Since the component is
>>> a new
>>> one, there is no id on the client side, but probably an ancestor could
>>> have an
>>> id set. The problem is the current algorithm does not have a standard
>>> way to
>>> check whether it has an id set on the client or not.
>>>
>>> But if a method like UIComponent.isClientIdRendered(...) exist, we could
>>> create
>>> an algorithm that recursively find the parent that needs to be rendered
>>> and
>>> include it into the current ajax request adding it to getRenderIds(). In
>>> that
>>> sense, the algorithm could automatically find that "content" needs to be
>>> updated and activate the render automatically.
>>>
>>>
>>> Going back to the main topic, getRenderIds() relies on a logic that for
>>> each
>>> id there is an html markup counterpart. setRenderTargetComponent(...)
>>> and getTargetComponentsToRender(...) are different because the intention
>>> here
>>> is to say "... this (resource) component needs to be added for this
>>> target,
>>> the way how you want to update the client is up to you ...".
>>>
>>> regards,
>>>
>>> Leonardo
>>>
>>> 2016-07-01 13:01 GMT-05:00 Neil Griffin <neil.griffin_at_portletfaces.org>:
>>>
>>>> Kyle Stiemann will also be commenting on the following issue in JIRA:
>>>> https://java.net/jira/browse/JAVASERVERFACES_SPEC_PUBLIC-1423
>>>>
>>>> Again, please click on the "watch" link in JIRA if you are interested.
>>>> Thanks.
>>>>
>>>> > On Jun 27, 2016, at 7:12 AM, Bauke Scholtz <balusc_at_gmail.com> wrote:
>>>> >
>>>> > As to "render target", isn't PartialViewContext#getRenderIds()
>>>> sufficient for the task? This returns a mutable collection of client IDs
>>>> which need to be updated on current partial request.
>>>> >
>>>> > Cheers, B
>>>> >
>>>> >
>>>> > On Mon, Jun 27, 2016 at 11:56 AM, Leonardo Uribe <
>>>> leonardo.uribe_at_irian.at> wrote:
>>>> > Hi
>>>> >
>>>> > 2016-06-24 10:35 GMT+02:00 Bauke Scholtz <balusc_at_gmail.com>:
>>>> > encodePartial() looks OK.
>>>> >
>>>> > I only don't understand how RequestViewContext, setRenderTarget() and
>>>> getComponentsToRender() are useful as compared to
>>>> UIViewRoot#addComponentResource()/getComponentResources().
>>>> >
>>>> >
>>>> > I haven't found good names for those ones but I'll explain the
>>>> intention of them.
>>>> >
>>>> > setRenderTarget(...) is used to indicate a component inside a
>>>> specified target needs to be updated on the client in the current partial
>>>> request. In comparison, addComponentResource(...) is used to add the
>>>> component to the tree.
>>>> >
>>>> > I know both methods look similar but they are not the same. The
>>>> reason is addComponentResource(...) is used to affect the component tree,
>>>> so it will be called each time the component tree is build (initial state,
>>>> delta, ...), and setRenderTarget(...) is used as a flag to indicate how the
>>>> current partial request must be rendered. Add a resource could cause the
>>>> flag to be activated, but not every call to addComponentResource(...) cause
>>>> the flag to be activated.
>>>> >
>>>> > Maybe a better name could be setRenderTargetComponent(...)
>>>> >
>>>> > getComponentsToRender(...) returns the list of the components bound
>>>> to an specific target that needs to be rendered on the current ajax
>>>> request. in comparison UIViewRoot.getComponentResources(...) return all
>>>> components bound to an specific target in the view.
>>>> >
>>>> > Maybe a better name could be getTargetComponentsToRender(...)
>>>> >
>>>> > These two methods are in fact more bound to UIViewRoot than to
>>>> FacesContext, but the data they manage is "transient", which means the data
>>>> is discarded at the end of the request.
>>>> >
>>>> > I also don't understand "You can't use an eval block because the
>>>> encoding does not work correctly". Which encoding exactly is problematic?
>>>> (there's at least character encoding, html encoding and javascript encoding
>>>> involved). Why couldn't that part be fixed instead?
>>>> >
>>>> >
>>>> > If you have a block like this:
>>>> >
>>>> > <h:outputScript target="head">
>>>> > script2 = function(){
>>>> > alert("script2");
>>>> > }
>>>> > </h:outputScript>
>>>> >
>>>> > you could try to do in code something like this:
>>>> >
>>>> > prwriter.startEval(....);
>>>> > renderChildren(...);
>>>> > prwriter.endEval();
>>>> >
>>>> > I tried but it doesn't work because you need to encode it properly,
>>>> but since there is a ResponseWriter outside of your control, you can't
>>>> encapsulate the script without do some nasty hacks over
>>>> ResponseWriter/PartialResponseWriter.
>>>> >
>>>> > In this case eval(...) does not work, so we need to attach the node
>>>> (well, if we want to fix this use case, which I think we should).
>>>> >
>>>> > regards,
>>>> >
>>>> > Leonardo Uribe
>>>> >
>>>> > Cheers, B
>>>> >
>>>> > On Thu, Jun 23, 2016 at 2:45 PM, Leonardo Uribe <
>>>> leonardo.uribe_at_irian.at> wrote:
>>>> > Hi
>>>> >
>>>> > Since there is already a solution almost completed in MyFaces (which
>>>> an small sample
>>>> > done some time ago) I did a prototype to see how it works and try to
>>>> find other details
>>>> > that could give us a better idea about what to do.
>>>> >
>>>> > From spec perspective the relevant changes are:
>>>> >
>>>> > UIComponent: Add the following methods:
>>>> >
>>>> > public void encodePartial(FacesContext context) throws IOException
>>>> >
>>>> > Default implementation call startUpdate(), encodeAll(), endUpdate();
>>>> >
>>>> > UIComponentBase: Add the following methods:
>>>> >
>>>> > public void encodePartial(FacesContext context) throws IOException
>>>> >
>>>> > Default implementation if renderer found call Renderer.encodePartial,
>>>> otherwise call
>>>> > super.encodePartial(...)
>>>> >
>>>> > Renderer: Add the following methods:
>>>> >
>>>> > public void encodePartial(FacesContext context, UIComponent component)
>>>> > throws IOException
>>>> >
>>>> > Default implementation call startUpdate(), encodeAll(), endUpdate();
>>>> >
>>>> > RequestViewContext: (it could be located in FacesContext)
>>>> >
>>>> > public void setRenderTarget(String target, boolean value,
>>>> > UIComponent component)
>>>> >
>>>> > public List<UIComponent> getComponentsToRender(String target);
>>>> > (it has an internal set to avoid duplicates, find a better name)
>>>> >
>>>> >
>>>> > The remaining tasks are implement encodePartial(...) for
>>>> h:outputScript,
>>>> > h:outputStylesheet, and update the implementation in
>>>> PartialViewContext to call
>>>> > encodePartial.
>>>> >
>>>> > This is a fragment of the generated response when the change
>>>> > is activated:
>>>> >
>>>> > <partial-response id="j_id__v_0"><changes><eval>
>>>> > <![CDATA[myfaces._impl.core._Runtime.loadScript(
>>>> > "/client-window-example/javax.faces.resource/script1.js.jsf", null,
>>>> null,
>>>> > "UTF-8", false);]]></eval><update id="content"><![CDATA[ ...
>>>> >
>>>> > The main page look like this:
>>>> >
>>>> > <h:commandLink id="page1" value="Page 1"
>>>> actionListener="#{ajaxContentBean.setPage1}">
>>>> > <f:ajax render=":content"/>
>>>> > </h:commandLink>
>>>> > ...
>>>> > <h:panelGroup id="content" layout="block">
>>>> > <ui:include src="#{ajaxContentBean.page}.xhtml" />
>>>> > </h:panelGroup>
>>>> >
>>>> > And the included page has something like this:
>>>> >
>>>> > <h:outputScript name="script1.js" target="head"/>
>>>> > <h:commandButton type="button" value="MSG" onclick="script1()"/>
>>>> >
>>>> > It works well for scripts but try to update something like this:
>>>> >
>>>> > <h:outputScript target="head">
>>>> > script2 = function(){
>>>> > alert("script2");
>>>> > }
>>>> > </h:outputScript>
>>>> >
>>>> > or this:
>>>> >
>>>> > <h:outputStylesheet name="style3.css"/> (target="head" is implicit)
>>>> >
>>>> > is the real problem. You can't use an eval block because the encoding
>>>> does not work
>>>> > correctly, so you really need to insert the DOM node. But the current
>>>> API in
>>>> > PartialResponseWriter is useless because head tag does not have an id
>>>> or name where you
>>>> > can grab.
>>>> >
>>>> > Ok, we can try to "make cheat" a little in this part and try:
>>>> >
>>>> > prwriter.startInsertAfter("javax.faces.ViewHead");
>>>> >
>>>> > but strictly speaking this should insert the html markup after
>>>> </head>, but we want
>>>> > the code inside. I just modified the js code to include it inside in
>>>> this case, but for
>>>> > a real implementation it is required to add some methods to
>>>> PartialResponseWriter like:
>>>> >
>>>> > public void startInsertFirst(String targetId) throws IOException
>>>> > public void startInsertLast(String targetId) throws IOException
>>>> >
>>>> > (find a better name, or maybe startInsertInsideAfter?, look in
>>>> another framework how
>>>> > they name this?)
>>>> >
>>>> > There is also another problem: How do you know you need to insert the
>>>> node instead of
>>>> > update it? The only clue is the node is processed specially in
>>>> PartialViewContext like
>>>> > this:
>>>> >
>>>> > List<UIComponent> componentsToRender =
>>>> rvc.getComponentsToRender("head");
>>>> >
>>>> > for (UIComponent resource: componentsToRender)
>>>> > {
>>>> > resource.encodePartial(_facesContext);
>>>> > }
>>>> >
>>>> > So, we need some flag or context attribute or something to indicate
>>>> we are attempting
>>>> > to include something new on the tree. Something like
>>>> JAVAX_FACES_INSERT_PARTIAL for
>>>> > example and something like JAVAX_FACES_UPDATE_TARGET, so the Renderer
>>>> in encodePartial
>>>> > can decide how to update the view.
>>>> >
>>>> > The partial response markup looks like this:
>>>> >
>>>> > <changes><insert><after id="javax.faces.ViewHead"><![CDATA[
>>>> > <script type="text/javascript">
>>>> > script2 = function(){
>>>> > alert("script2");
>>>> > }
>>>> > </script>]]></after></insert>
>>>> >
>>>> > It should be better
>>>> >
>>>> > <changes><insert><last id="javax.faces.ViewHead"><![CDATA[<script
>>>> type="text/javascript">
>>>> > script2 = function(){
>>>> > alert("script2");
>>>> > }
>>>> > </script>]]></last></insert>
>>>> >
>>>> > And that's it the proposal from MyFaces side. I think it is flexible
>>>> enough to allow the
>>>> > algorithm using "two lists comparison", but also enough to allow the
>>>> implementation
>>>> > inside MyFaces.
>>>> >
>>>> >
>>>> > But note the issue proposed here:
>>>> >
>>>> > JAVASERVERFACES_SPEC_PUBLIC-1404 Add
>>>> UIViewRoot#getRenderedComponentResources()
>>>> >
>>>> > is still valid. But I'll send the comments related to that one in
>>>> other email.
>>>> >
>>>> >
>>>> > Suggestions are welcomed.
>>>> >
>>>> > regards,
>>>> >
>>>> > Leonardo Uribe
>>>> >
>>>> >
>>>> >
>>>> > 2016-06-22 9:19 GMT+02:00 Cagatay Civici <cagatay.civici_at_gmail.com>:
>>>> > Sure, actually Thomas Andraschko, the reporter of
>>>> JAVASERVERFACES_SPEC_PUBLIC-1423 has implemented it in PF, I’ve asked him
>>>> for details and his response briefly is;
>>>> >> Have a look at:
>>>> >> org.primefaces.application.resource.DynamicResourcesPhaseListener -
>>>> it collects the initial resources on the ajax request
>>>> >> org.primefaces.context.PrimePartialResponseWriter - ln 278; gets the
>>>> resources again, creates a diff of the initial and new resources, render
>>>> some JS to load the resources dynamically
>>>> > Regards,
>>>> >
>>>> > Cagatay Civici
>>>> > PrimeFaces Lead
>>>> > PrimeTek Informatics
>>>> > On Wednesday 22 June 2016 at 10:02, Bauke Scholtz wrote:
>>>> >
>>>> >> Cagatay, can you point out it in the PrimeFaces codebase? Then I
>>>> will look at similarities and differences and if necessary optimize the
>>>> standard solution based on that.
>>>> >>
>>>> >> Cheers, B
>>>> >>
>>>> >>
>>>> >> On Wed, Jun 22, 2016, 08:43 Cagatay Civici <cagatay.civici_at_gmail.com>
>>>> wrote:
>>>> >>> We also have a custom solution to this in PrimeFaces as it is a
>>>> very common case. A standard solution would be preferred for sure.
>>>> >>>
>>>> >>> Regards,
>>>> >>>
>>>> >>> Cagatay Civici
>>>> >>> PrimeFaces Lead
>>>> >>> PrimeTek Informatics
>>>> >>> On Tuesday 21 June 2016 at 22:34, Bauke Scholtz wrote:
>>>> >>>
>>>> >>>> Coming to it, a new encodeAjax() method in UIComponent and
>>>> Renderer (I'd rather call it encodePartial(), in line with the existing
>>>> API) is a great suggestion which could indeed solve this problem and has
>>>> potential for solving/optimizing ajax based problems in a much more
>>>> flexible way. This is indeed a small and easy change in the API (and impl).
>>>> >>>>
>>>> >>>> +1 from me.
>>>> >>>>
>>>> >>>> Cheers, B
>>>> >>>>
>>>> >>>>
>>>> >>>>
>>>> >>>>
>>>> >>>> On Tue, Jun 21, 2016 at 5:22 PM, Bauke Scholtz <balusc_at_gmail.com>
>>>> wrote:
>>>> >>>>> As to writer.startEval(), as per
>>>> https://java.net/jira/browse/JAVASERVERFACES_SPEC_PUBLIC-1412 I've
>>>> added a PartialViewContext#getEvalScripts() for JSF 2.3. This could be used.
>>>> >>>>>
>>>> >>>>> I will think about encodeAjax() and reply later.
>>>> >>>>>
>>>> >>>>> Cheers, B
>>>> >>>>>
>>>> >>>>> On Tue, Jun 21, 2016 at 4:01 PM, Leonardo Uribe <
>>>> leonardo.uribe_at_irian.at> wrote:
>>>> >>>>>> Hi
>>>> >>>>>>
>>>> >>>>>> I just wanted to repost a comment from MyFaces issue tracker in
>>>> 2012 about the issue being discussed now:
>>>> >>>>>>
>>>> >>>>>>
>>>> >>>>>> Luciano Deiru:
>>>> >>>>>>
>>>> >>>>>> Thanks for the reply.
>>>> >>>>>>
>>>> >>>>>> I don't think it's going to be possible for me to migrate my app
>>>> to JSF2 without a
>>>> >>>>>> complete re-write of the frontend. I did a little more digging
>>>> to see if richfaces was
>>>> >>>>>> the issue and i can across this section of the richfaces 4.2.2
>>>> development guide...
>>>> >>>>>> ...
>>>> >>>>>>
>>>> >>>>>> "JSF 2 does not allow resources such as JavaScript or Cascading
>>>> Style Sheets (CSS) to
>>>> >>>>>> be added if the element requiring the resource is not initially
>>>> present in the JSF
>>>> >>>>>> tree. As such, components added to the tree via Ajax must have
>>>> any required resources
>>>> >>>>>> already loaded. In RichFaces, any components added to the JSF
>>>> tree should have
>>>> >>>>>> components with corresponding resources included on the main
>>>> page initially. To
>>>> >>>>>> facilitate this, components can use the rendered="false"
>>>> setting to not be
>>>> >>>>>> rendered on the page."
>>>> >>>>>> ...
>>>> >>>>>>
>>>> >>>>>> So the only workaround would be to add every possible richfaces
>>>> and primefaces component
>>>> >>>>>> to the login page so it loads the JS and css. That's a bit
>>>> depressing because you
>>>> >>>>>> can't create a "pure ajax"/dynamic application in JSF2 even tho
>>>> i was possible in JSF1.
>>>> >>>>>> It seems like a widely used approach and there are a lot of
>>>> forum posts about the
>>>> >>>>>> issue but no one is ever able to get it working without
>>>> including the hidden components.
>>>> >>>>>>
>>>> >>>>>>
>>>> >>>>>> regards,
>>>> >>>>>>
>>>> >>>>>> Leonardo Uribe
>>>> >>>>>>
>>>> >>>>>> 2016-06-21 15:55 GMT+02:00 Leonardo Uribe <
>>>> leonardo.uribe_at_irian.at>:
>>>> >>>>>>> Hi
>>>> >>>>>>>
>>>> >>>>>>> I see.
>>>> >>>>>>>
>>>> >>>>>>> BS>> Also, to avoid duplicates and/or unnecessary re-rendering,
>>>> all so far rendered
>>>> >>>>>>> BS>> resources must be remembered in JSF state. AFAIC this is
>>>> currently not the case.
>>>> >>>>>>>
>>>> >>>>>>> Well, this is information related to the view that is implicit
>>>> there, but you want to
>>>> >>>>>>> avoid to put it in the state.
>>>> >>>>>>>
>>>> >>>>>>> That's the reason why I like the way it is working in MyFaces,
>>>> because we just keep
>>>> >>>>>>> track of the change, rather than store that information in the
>>>> state.
>>>> >>>>>>>
>>>> >>>>>>> Write the script directly into the <eval> is possible, but
>>>> right now from spec
>>>> >>>>>>> perspective there are not the necessary "building blocks"
>>>> available.
>>>> >>>>>>>
>>>> >>>>>>> Both h:outputScript and h:outputStylesheet are components that
>>>> are supposed to be
>>>> >>>>>>> rendered as resources, but both components have Renderer
>>>> instances, which are
>>>> >>>>>>> the classes who finally decide how they should be rendered.
>>>> Even if you have a list,
>>>> >>>>>>> this list could include javascript/css or whatever and the
>>>> resources could be rendered
>>>> >>>>>>> in different ways.
>>>> >>>>>>>
>>>> >>>>>>> For example an h:outputScript could have children that could be
>>>> js code. Or a
>>>> >>>>>>> h:outputStylesheet could have a "media" property set.
>>>> >>>>>>>
>>>> >>>>>>> So if we want a "general" solution to the problem, which
>>>> includes script, stylesheets
>>>> >>>>>>> or whatever, it is necessary to know the component instance
>>>> that needs to be added
>>>> >>>>>>> or updated, and then ask the component how it should be
>>>> rendered.
>>>> >>>>>>>
>>>> >>>>>>> The problem from the "building blocks" perspective, is there is
>>>> no way the component
>>>> >>>>>>> can know the current request is an ajax update. encodeAll(...)
>>>> just means encode
>>>> >>>>>>> everything and don't ask questions.
>>>> >>>>>>>
>>>> >>>>>>> I would like to have a method in UIComponent/Renderer called
>>>> encodeAjax(...) for the
>>>> >>>>>>> component, which by default start and end an <update> section
>>>> and call by default
>>>> >>>>>>> to encodeAll(...). Something like this
>>>> >>>>>>>
>>>> >>>>>>> public void encodeAjax(FacesContext _facesContext,
>>>> PartialResponseWriter writer) {
>>>> >>>>>>> try
>>>> >>>>>>> {
>>>> >>>>>>> writer.startUpdate(target.getClientId(_facesContext));
>>>> >>>>>>> target.encodeAll(_facesContext);
>>>> >>>>>>> }
>>>> >>>>>>> finally
>>>> >>>>>>> {
>>>> >>>>>>> writer.endUpdate();
>>>> >>>>>>> }
>>>> >>>>>>> }
>>>> >>>>>>>
>>>> >>>>>>> This part is done in PartialViewContext implementation, but if
>>>> we can move it here
>>>> >>>>>>> we could ask the component in a gentle way how it should be
>>>> rendered. Then, from
>>>> >>>>>>> this location we could override the method and call
>>>> writer.startEval(...), which is
>>>> >>>>>>> something is not possible in this moment, because there is no
>>>> way right now to
>>>> >>>>>>> customize this step for each component.
>>>> >>>>>>>
>>>> >>>>>>> In this way, you could add an script to load the stylesheet and
>>>> then use the eval
>>>> >>>>>>> to include it in the response.
>>>> >>>>>>>
>>>> >>>>>>> I have already mention this improvement in this mail some time
>>>> ago:
>>>> >>>>>>>
>>>> >>>>>>>
>>>> https://java.net/projects/javaserverfaces-spec-public/lists/jsr372-experts/archive/2015-04/message/41
>>>> >>>>>>>
>>>> >>>>>>> It looks we have yet another use case where this could be
>>>> useful.
>>>> >>>>>>>
>>>> >>>>>>> regards,
>>>> >>>>>>>
>>>> >>>>>>> Leonardo Uribe
>>>> >>>>>>>
>>>> >>>>>>>
>>>> >>>>>>> 2016-06-21 14:51 GMT+02:00 Bauke Scholtz <balusc_at_gmail.com>:
>>>> >>>>>>>> Hi,
>>>> >>>>>>>>
>>>> >>>>>>>> OmniFaces has 3 solutions to dynamically include a (script)
>>>> resource:
>>>> >>>>>>>>
>>>> >>>>>>>> 1: Ajax#load() (just write script straight to <eval>)
>>>> >>>>>>>> 2: Components#addScriptResourceToHead()
>>>> >>>>>>>> 3: Components#addScriptResourceToBody()
>>>> >>>>>>>>
>>>> >>>>>>>> Which one to use depends on the moment (which isn't yet
>>>> refactored into a single utility method, this is TBD). When the request is
>>>> an ajax request with partial rendering (i.e. ajax with NO @all), then use
>>>> #1. Else when the current phase is NOT render response, or the view is in
>>>> BUILDING state, then use #2. Else use #3.
>>>> >>>>>>>>
>>>> >>>>>>>> This is implemented for the unload script associated with
>>>> OmniFaces @ViewScoped and this works quite well.
>>>> >>>>>>>>
>>>> >>>>>>>> Also, to avoid duplicates and/or unnecessary re-rendering, all
>>>> so far rendered resources must be remembered in JSF state. AFAIC this is
>>>> currently not the case.
>>>> >>>>>>>>
>>>> >>>>>>>> Cheers, B
>>>> >>>>>>>>
>>>> >>>>>>>>
>>>> >>>>>>>> On Tue, Jun 21, 2016 at 2:37 PM, Leonardo Uribe <
>>>> leonardo.uribe_at_irian.at> wrote:
>>>> >>>>>>>>> Hi
>>>> >>>>>>>>>
>>>> >>>>>>>>> I have seen this issue has been opened in the spec issue
>>>> tracker
>>>> >>>>>>>>>
>>>> >>>>>>>>> https://java.net/jira/browse/JAVASERVERFACES_SPEC_PUBLIC-1423
>>>> >>>>>>>>> Dynamic resource loading in ajax requests
>>>> >>>>>>>>>
>>>> >>>>>>>>> I would like to contribute with some thoughts about the
>>>> topic, since in MyFaces there
>>>> >>>>>>>>> is a solution that is not perfect (if PartialViewContext is
>>>> overriden, the code will
>>>> >>>>>>>>> not work, so some third party libraries will not be able to
>>>> use it), but it helps to
>>>> >>>>>>>>> identify the missing points in the spec, and specify it
>>>> faster.
>>>> >>>>>>>>>
>>>> >>>>>>>>> This issue could be also relevant for portlets.
>>>> >>>>>>>>>
>>>> >>>>>>>>> The issue has been reported long time ago in:
>>>> >>>>>>>>>
>>>> >>>>>>>>> - https://issues.apache.org/jira/browse/MYFACES-3106
>>>> >>>>>>>>> Resources not loaded when using a dynamic ui:inlclude and
>>>> rendered via ajax
>>>> >>>>>>>>>
>>>> >>>>>>>>> - https://issues.apache.org/jira/browse/MYFACES-3367
>>>> >>>>>>>>> Detect when to update head or body target when content has
>>>> been updated dynamically
>>>> >>>>>>>>>
>>>> >>>>>>>>> - https://issues.apache.org/jira/browse/MYFACES-3659
>>>> >>>>>>>>> Conditional include of scripts and stylesheets
>>>> >>>>>>>>>
>>>> >>>>>>>>> The first thing to understand the problem is identify the
>>>> possible use cases we have:
>>>> >>>>>>>>>
>>>> >>>>>>>>> - c:if, ui:include src="#{...}" or facelet tag that
>>>> dynamically update the tree.
>>>> >>>>>>>>>
>>>> >>>>>>>>> For example:
>>>> >>>>>>>>>
>>>> >>>>>>>>> ...
>>>> >>>>>>>>> <f:ajax event="onclick" render="box"/>
>>>> >>>>>>>>> ...
>>>> >>>>>>>>>
>>>> >>>>>>>>> <div jsf:id="box">
>>>> >>>>>>>>> <c:if test="#{...}">
>>>> >>>>>>>>> <h:outputScript target="head" library="js" name="help.js"
>>>> />
>>>> >>>>>>>>>
>>>> >>>>>>>>> ...
>>>> >>>>>>>>> </c:if>
>>>> >>>>>>>>> </div>
>>>> >>>>>>>>>
>>>> >>>>>>>>> Here we have a case when the components inside the c:if
>>>> requires some javascript file,
>>>> >>>>>>>>> but the update comes from an ajax request. The algorithm just
>>>> somehow put the
>>>> >>>>>>>>> h:outputScript on the head of the document, but the ajax does
>>>> not trigger the head
>>>> >>>>>>>>> refresh, so the component was added to the tree, but the
>>>> javascript file was not loaded
>>>> >>>>>>>>> and we finally have a broken panel.
>>>> >>>>>>>>>
>>>> >>>>>>>>> There are variants of the same example with
>>>> h:outputStylesheet, or ui:include but the
>>>> >>>>>>>>> reason is the same.
>>>> >>>>>>>>>
>>>> >>>>>>>>> - Dynamic but the resource is added by a @ResourceDependency
>>>> annotation.
>>>> >>>>>>>>>
>>>> >>>>>>>>> This is similar to the previous case, but the component is
>>>> added indirectly when
>>>> >>>>>>>>> Application.createComponent(...) is executed.
>>>> >>>>>>>>>
>>>> >>>>>>>>> The important thing to keep in mind is there are 3 possible
>>>> targets: "head", "body" and
>>>> >>>>>>>>> "form". But the only thing we can do with the current spec is
>>>> just force a full update
>>>> >>>>>>>>> of each of these targets.
>>>> >>>>>>>>>
>>>> >>>>>>>>> So, in MyFaces there is a web config param called
>>>> >>>>>>>>> org.apache.myfaces.STRICT_JSF_2_REFRESH_TARGET_AJAX that when
>>>> it is activated, and
>>>> >>>>>>>>> the previous situation happens, it just enable a flag so the
>>>> target is updated with
>>>> >>>>>>>>> the ajax request. If the "head" needs to be updated, the
>>>> whole "head" and the updated
>>>> >>>>>>>>> content is sent and so on.
>>>> >>>>>>>>>
>>>> >>>>>>>>> The processing is done on process partial render time, after
>>>> the ajax request is
>>>> >>>>>>>>> rendered but before write the state token. Please note if the
>>>> target is rendered before
>>>> >>>>>>>>> this code, the algorithm should be able to detect the
>>>> condition and do not duplicate
>>>> >>>>>>>>> the response.
>>>> >>>>>>>>>
>>>> >>>>>>>>> The solution is not perfect because it force render the whole
>>>> target, when we only
>>>> >>>>>>>>> need to render the html fragment of the added component
>>>> (script/stylesheet/
>>>> >>>>>>>>> other js code). But there is no way to do it with the current
>>>> API, because <head>
>>>> >>>>>>>>> or <body> could not have an id and without id, you can't
>>>> insert. PartialResponseWriter
>>>> >>>>>>>>> contains these methods:
>>>> >>>>>>>>>
>>>> >>>>>>>>> startInsertBefore(String targetId)
>>>> >>>>>>>>> startInsertAfter(String targetId)
>>>> >>>>>>>>>
>>>> >>>>>>>>> But note these two are useless, because what we need is
>>>> insert "inside" at the beginning
>>>> >>>>>>>>> or the end.
>>>> >>>>>>>>>
>>>> >>>>>>>>> For example:
>>>> >>>>>>>>>
>>>> >>>>>>>>> <head>
>>>> >>>>>>>>>
>>>> >>>>>>>>> <script .../>
>>>> >>>>>>>>> </head>
>>>> >>>>>>>>>
>>>> >>>>>>>>> <body>
>>>> >>>>>>>>> <script .../>
>>>> >>>>>>>>>
>>>> >>>>>>>>> </body>
>>>> >>>>>>>>>
>>>> >>>>>>>>> Please note there are some cases where the jsf third party
>>>> library (for example
>>>> >>>>>>>>> primefaces) provides its own rules to to render the script at
>>>> first, middle or last. But
>>>> >>>>>>>>> in this case it doesn't matter those rules, because what we
>>>> really need is that the
>>>> >>>>>>>>> resource is added.
>>>> >>>>>>>>>
>>>> >>>>>>>>> The code that activates the flags to render head, body or
>>>> form target is on
>>>> >>>>>>>>> h:outputScript and h:outputStylesheet, specifically in the
>>>> listener attached to
>>>> >>>>>>>>> PostAddToViewEvent. This is the best place, because here is
>>>> the place where
>>>> >>>>>>>>> UIViewRoot.addComponentResource is done.
>>>> >>>>>>>>>
>>>> >>>>>>>>>
>>>> >>>>>>>>>
>>>> >>>>>>>>> I think what's really important in this problem is provide
>>>> the API where you can notify
>>>> >>>>>>>>> that the resource needs to be added. In MyFaces there is:
>>>> >>>>>>>>>
>>>> >>>>>>>>> class RequestViewContext {
>>>> >>>>>>>>>
>>>> >>>>>>>>> public boolean isRenderTarget(String target);
>>>> >>>>>>>>>
>>>> >>>>>>>>> public void setRenderTarget(String target, boolean value);
>>>> >>>>>>>>>
>>>> >>>>>>>>> }
>>>> >>>>>>>>>
>>>> >>>>>>>>> Which could evolve to something more complex, including the
>>>> UIComponent instance and
>>>> >>>>>>>>> so on.
>>>> >>>>>>>>>
>>>> >>>>>>>>> I don't really like to do a list comparison, because it can
>>>> introduce an unnecessary
>>>> >>>>>>>>> performance overhead. I would like an API that could have
>>>> some methods to register the
>>>> >>>>>>>>> component for updated on the target and others to get the
>>>> changes and do the necessary
>>>> >>>>>>>>> calculation in PartialViewContext.processPartial(...) (render
>>>> response).
>>>> >>>>>>>>>
>>>> >>>>>>>>> regards,
>>>> >>>>>>>>>
>>>> >>>>>>>>> Leonardo Uribe
>>>> >>>>>>>>
>>>> >>>>>>>
>>>> >>>>>>
>>>> >>>>>
>>>> >>>>
>>>> >>>
>>>> >
>>>> >
>>>> >
>>>> >
>>>> >
>>>>
>>>>
>>>
>>
>