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

[jsr344-experts] [1111-PassThruElements] DISCUSSION

From: Andy Schwartz <andy.schwartz_at_oracle.com>
Date: Fri, 08 Jun 2012 19:23:10 -0400

Changing the subject line to:

> [1111-PassThruElements] DISCUSSION

Since this seems to be more in line with that thread

On 6/8/12 2:25 PM, Blake Sullivan wrote:
> I think that the jsfc and passThru attribute discussions suggest two
> different use cases:
> 1) Annotating/overriding the output of the rendering of normal JSF
> components (the passThru attribute case)
> 2) Associating JSF components with HTML markup (the current jsfc case)
>
> For the second of these, I question what jsfc is bringing to the table

Before jumping into Blake's comments, I wanted to go back to something
that Ed mentioned earlier:

> The jsfc feature crept in when we adopted Facelets, but it was never
> given the true attention it deserved because not all EG members liked
> it.

Pretty sure I must have been one of the EG members who expressed doubts
about this feature. My dislike for jsfc is not because I am opposed to
the idea of facilitating HTML-centric page authoring, but because I
don't actually think that jsfc helps nearly as much as it should. jsfc
gives the impression that JSF/Facelets supports an HTML-centric
authoring model. However, this model falls on its face way too quickly.

Let's look at a simple example...

Say a web designer codes the following bit of HTML:

  <input class="business-input" type="email">

And also defines some styles for the ".business-input" CSS selector.

The content looks great, yay!

Time to hand off to the JSF app developer.

The app developer wants to minimize the amount of changes to the page
content and cleverly decides to use jsfc:

  <input class="business-input" type="email" value="#{el.to.value}
jsfc="h:inputText">

Yay! That was so easy!

Oh, wait... you actually wanted the honor those style class and type
attributes?

Really?!?

Because I was thinking that we would just stash those attributes away in
the UIComponent's attribute map, never to be seen again.

Sigh.

As we look to enhance (or replace?) jsfc, I hope that we can keep this
simple, yet fundamental, limitation in mind.


> if we simply say that the presence of a component attribute implies
> the presence of a component:
> <div class="comp-div" data-foo="bar" c:rendered="#{el.to.rendered}">
> If a page author wants to use template markup with the odd component,
> this seems sufficient.

One thing that that would be nice about using the presence of
"component" (c: namespaced) attributes to drive component creation is
that allows us to break away from the existing jsfc attribute handling
contract (rather than break this).


> The only slightly wonky bit has to do with ids, since the renderer
> wants to own the id in order to apply the naming container rules. For
> example, this could lead to trouble:
>
> <div *id="myDiv"* class="comp-div" data-foo="bar" c:rendered="#{el.to.rendered}">
> For clarity reasons, I would propose that in cases where a component
> is associated with the markup, we disallow id and suggest c:id instead:
> <div *c:id="myDiv"* class="comp-div" data-foo="bar" c:rendered="#{el.to.rendered}">

Ids are definitely weird. I do like the idea that this:

  <div c:id="foo">

Would be the minimally sufficient content to force a <div> pass through
element/component to be created. Nice.


> Of course, if we aren't using jsfc, there is the question of how
> associate the component (and renderer) with the markup.

Right.


> We could just require the use of JSFc and be done with it, but if
> our goal is to make things as simple as possible for page authors, why
> would we? It would seem preferable to use the markup to associate the
> component for the page author by default.

Yep. I would love to see something as simple as:

  <button c:action="#{el.to.action}>

For creating a "command" button, without the page author being forced to
explicitly declare jsfc="h:commandButton".

Though this means that we need to design a mapping mechanism that the
Facelets compiler could use to translate from arbitrary markup
elements/attributes to corresponding JSF components/attributes. This
mechanism would need to be configurable in such a way that the above
<button> content could be re-mapped from h:commandButton to an
equivalent 3rd party button component.


> If the page author wants a different component, she can use the jsfc
> attribute (which maybe should be c:jsfc to do so).
>
> That actually leads to four more questions (with my opinions)
> 1) Should the Renderer actually be rendering anything (other than the
> clientId) (probably not--the page author already specified her markup)

I wonder whether there are cases where the Renderer is going to want to
enhance the markup. For example, it would be nice if we had some way to
translate:

  <a href="#" c:action="#{el.to.action}">

Into a "command" link, but that would require rendering some JavaScript
code to do the submit.

> 2) Should the non-component attributes be present on the component
> instance (as passThru attributes?) (yes)

Yep, this is key. Though wondering whether there are cases where we
would want to allow mappings from HTML attributes to component
attributes to be performed at Facelets compilation time.

> 3) If we are already associating the html markup with the components,
> should we work harder to map the HTML attributes to component
> attributes (yes)

Oh. Yeah. Guess that was my reaction to #2. :-)

> 4) Should we support an explicit jsfc value for "use the default
> component/renderer combinations). (yes c:jsfc="auto" or some such)

I guess this is in the case where no other c: attribute is specified?

> Here is an example of component mapping:
>
> <input c:id="name" type=text" value="#{myBean.name}" disabled="disabled"/>
>
> I think that a page author might reasonably expect that the markup
> would have an associated inputText conponent with a valueExpression
> that writes back into the managed bean and sets the disabled attribute
> to true.

Yep.

> This does potentially cause problems if we are sticking the pass
> through attributes into the the pass thru map on the component--we
> don't want the same attribute in two different places. I would say
> that only the "type" attribute ends up in the passThru map in this
> case. The downside of this is that it is probably not clear which
> attributes should end up in the passThru map vs. being consumed. This
> can also cause backwards compatibility problems if we add a component
> attribute at a later point in time and would like to map it from
> HTML.... That blows. I change my mind--I would say that all
> non-explicit component attributes populate the passThru map but the
> attributes are not bidirectional with the component attributes.

Need to think about this some more.

If we are hoping to tackle this area, we probably need to start by
trying to identify the range of use cases that we hope to cover. Simple
div/input/button cases are one thing. What about more complex
components - eg. tables, or components that have no equivalent in HTML
land? How far do we hope to take this?

BTW, another way to remove complexity from the page content would be to
make it easier to move component configuration to Java code. Thinking
particularly about being able to move verbose JSF markup like:

  <button jsf="h:commandButton">
    <f:ajax event="action" render="foo bar" execute="foo bar"/>
  </button>

Out of the page.

Sure, this is possible with component bindings:

  <button jsfc="h:commandButton" binding="#{el.to.component}">

However, JSF's component binding mechanism is too complex/too easy to
get wrong. I'm thinking that there is some way that we could do this that:

- Would not require the use of EL expressions.
- Would automatically ensure that dynamically configured components do
not end up in an inappropriate scope (eg. no session scope UIComponents)

Also thinking that more fluent Java APIs for UIComponents, Converters,
Validaters, Behaviors would go a long way to simplifying this.

Andy

>
> -- Blake Sullivan
>