javaserverfaces-spec-public
  1. javaserverfaces-spec-public
  2. JAVASERVERFACES_SPEC_PUBLIC-770

add component resources depending on the owner component state

    Details

    • Type: Bug Bug
    • Status: Open
    • Priority: Minor Minor
    • Resolution: Unresolved
    • Affects Version/s: 2.0
    • Fix Version/s: None
    • Component/s: Components/Renderers
    • Labels:
      None
    • Environment:

      Operating System: All
      Platform: All

    • Issuezilla Id:
      770
    • Status Whiteboard:
      Hide

      size_large importance_small

      Show
      size_large importance_small

      Description

      All this text is extracted from jsr-314-open mailing list and it is put here as
      reference.

      [jsr-314-open] add component resources depending on the owner component state

      Trying to use the new JSF 2.0 Resource Api I have found one case that maybe it
      is of interest on this list.

      Suppose a component that needs to add some specific javascript/css file based on
      a value. In tomahawk we can do it something like this on the renderer:

      if( tabbedPane.isClientSide() ){
      addResource.addJavaScriptAtPosition(facesContext,
      AddResource.HEADER_BEGIN, HtmlTabbedPaneRenderer.class, "dynamicTabs.js");

      This code works because the response is buffered and post-processed.

      The problem is how to do that with JSF 2.0?

      One could think on use a listener attached to PreRenderComponentEvent, but this
      event is called before encodeBegin, so it is useless in this case, because we
      need to call it before the whole view is rendered.

      Then, you can think do something like this:

      @ListenerFor(systemEventClass = PreRenderViewEvent.class)
      public class HtmlTabbedPaneRenderer extends HtmlRenderer
      ......

      It does not work too. The reason is the listener is attached to the component
      instance, and only the UIViewRoot instance receives the event. If we do the same
      as f:event does when PreRenderViewEvent is found (suscribe the listener on
      UIViewRoot) we lose the component we are referencing, because it is replaced by
      UIViewRoot.

      I can solve this one creating a wrapper for ViewHandler that publish a custom
      event for all components before render view. but the big question is if jsf 2.0
      should support this use case out of the box.

      >> Cagatay Civici
      >> Why not listening to PostAddToViewEvent with;
      >>
      >>
      >> @ListenerFor(systemEventClass = PostAddToViewEvent.class)
      >>public class HtmlTabbedPane extends UIComponentBase

      { >>}

      >>
      >> and in event listener;
      >>
      >> if(this.isClientSide()) {
      >> viewroot.addComponentResource(...);
      >>

      Does not work too because in a postback, PostAddToViewEvent occur in the
      following cases:

      • With Partial State Saving enabled when the view is build but before the state
        of the component is restored.
      • With Partial State Saving disabled when the view is "refreshed", because all
        component nodes are detached and attached to the tree.

      Now suppose the component has a ValueExpression attached to the property, and
      the value changes on Invoke Application Phase. With partial state saving the
      tree was already build, so it doesn't catch the logic. With partial state saving
      disabled, the event occur twice, the first time when the tree structure is
      build, the second time when the view is updated, so again it doesn't work,
      because if the resource component (it is transient too) was already added, it
      cannot be removed later.

      >> Ed Burns
      >>
      >>Please correct me if I'm wrong, but the problem you state above seems to
      >>be just another example of the garden variety "conditional value changes
      >>between requests or during a request".
      >>

      Yes and no. The difference with other examples of the garden is to add a
      component resource, we need to do it in the right time, since it requires to
      update the component tree adding components before render it, but after we know
      which view will be rendered. Please note by a previous fix, all component
      resources are transient.

      As a side note, if someone wants to do this in a composite component he/she
      probable do this:

      <c:if test="#

      {cc.attrs.....}

      ">
      <h:outputStylesheet ..../>
      </c:if>

      And it works in myfaces because we have a fix for the c:if problem.

      >> Do we need PreAddComponentResourceEvent and
      >> PostAddComponentResourceEvent?

      In my opinion is only necessary to add only one event. The right place is after
      resolve PreRenderViewEvent, because only in that time we know the current
      component tree is the view that will be rendered.

      It is not possible to use PreRenderComponentEvent because it is called on
      encodeBegin and the view header was already rendered.

      It is not possible to use PreRenderViewEvent like this:

      @ListenerFor(systemEventClass = PreRenderViewEvent.class)
      public class HtmlTabbedPaneRenderer extends HtmlRenderer

      because the listener is attached to the component when it is created, but the
      event is only received by the current UIViewRoot. If we fix the algorithm on
      Application class to attach this listener to the current UIViewRoot instance,
      the source of the event will be UIViewRoot, and traverse the tree to find the
      component is worse. Note other option is publish PreRenderViewEvent for all
      child components, but after know the view that will be rendered.

      In conclusion, for make this use case possible we need two things:

      1. The right time to add the resource to the component tree.
      2. The component with its state restored and updated.

      Thinking more about it, another option about put this code could be on
      vld.buildView method, but note when partial state saving is enabled this method
      return immediately (maybe it is possible to change it).

        Activity

        lu4242 created issue -
        Hide
        Ed Burns added a comment -

        Move to 2.1

        Show
        Ed Burns added a comment - Move to 2.1
        Hide
        Ed Burns added a comment -

        triage

        Show
        Ed Burns added a comment - triage
        Hide
        Ed Burns added a comment -

        rogerk

        Show
        Ed Burns added a comment - rogerk
        Hide
        rogerk added a comment -

        triage

        Show
        rogerk added a comment - triage
        Hide
        rogerk added a comment -

        triage

        Show
        rogerk added a comment - triage
        kenaiadmin made changes -
        Field Original Value New Value
        issue.field.bugzillaimportkey 770 20375
        Ed Burns made changes -
        Assignee rogerk [ rogerk ]
        Ed Burns made changes -
        Fix Version/s 2.3 [ 16372 ]
        Fix Version/s 2.2 [ 10403 ]
        Hide
        Ed Burns added a comment -

        Set priority to baseline ahead of JSF 2.3 triage. Priorities will be assigned accurately after this exercise.

        Show
        Ed Burns added a comment - Set priority to baseline ahead of JSF 2.3 triage. Priorities will be assigned accurately after this exercise.
        Ed Burns made changes -
        Priority Major [ 3 ] Trivial [ 5 ]
        Fix Version/s 2.3 [ 16372 ]
        Ed Burns made changes -
        Priority Trivial [ 5 ] Minor [ 4 ]

          People

          • Assignee:
            Unassigned
            Reporter:
            lu4242
          • Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

            Dates

            • Created:
              Updated: