QeelwaEtech / omnifaces

Automatically exported from code.google.com/p/omnifaces
0 stars 1 forks source link

Composite component for encapsulating one or more input components #139

Closed GoogleCodeExporter closed 9 years ago

GoogleCodeExporter commented 9 years ago
Composite component for handling h:label / input / h:message linking would be 
nice.

Something similar to Seam 2 s:decorate [1] or Seam 3 UIInputContainer [2].

See [3] for a sample usage of UIInputContainer.

Omnifaces seems to be the place for such a component :
 * it's a utility, so it doesn't belongs to RF / PF / Icefaces.
 * it's only JSF related, so no Deltaspike.
 * Seam 3 is dead, so we cannot use UIInputContainer (I copy it in every project).

Thanks very much for taking this into consideration.

N.B. : As a warning, JSF impls have some bugs when handling composite 
components, so our version of UIInputContainer is quite patched (see see 
SEAMFACES-250, JAVASERVERFACES-2142, JAVASERVERFACES-2689 and MYFACES-3027).

[1] http://docs.jboss.org/seam/2.3.0.Final/reference/en-US/html/validation.html

[2] 
http://docs.jboss.org/seam/3/latest/reference/en-US/html/components.html#UIInput
Container

[3] 
<field:edit id="nom" label="#{messages['chargeClientele.nom.label']}">
  <h:inputText id="input" value="#{chargeClienteleController.instance.nom}" styleClass="input-small" required="true"/>
</field:edit>

with resources/components/field/edit.xhtml being

<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
  xmlns:ui="http://java.sun.com/jsf/facelets"
  xmlns:f="http://java.sun.com/jsf/core"
  xmlns:h="http://java.sun.com/jsf/html"
  xmlns:c="http://java.sun.com/jsp/jstl/core"
  xmlns:cc="http://java.sun.com/jsf/composite">

  <cc:interface componentType="com.natixis.sphinx.jsf.InputContainer">
    <cc:attribute name="label" required="true" />
    <cc:attribute name="inputs" default="1" />
    <cc:attribute name="labelClass"/>
    <cc:attribute name="enclose" default="true"/>
    <cc:attribute name="styleClass" default="control-group #{cc.attrs.invalid ? 'error' : ''}"/>
  </cc:interface>
  <cc:implementation>
    <h:outputLabel id="label" for="" styleClass="control-label #{cc.attrs.labelClass}">
      <ui:fragment rendered="#{cc.attrs.invalid}">
        <i class="icon-msg-err"></i>
      </ui:fragment>
      #{cc.attrs.label} 
      <h:panelGroup styleClass="required" rendered="#{cc.attrs.required}">*</h:panelGroup> : 
    </h:outputLabel>
    <div class="controls">
      <ui:fragment>
        <cc:insertChildren />
      </ui:fragment>
      <ui:fragment rendered="#{cc.attrs.invalid}">
        <p class="help-block"><h:message id="message#{1}" for=""/></p>
      </ui:fragment>
    </div>
  </cc:implementation>
</ui:composition>

Original issue reported on code.google.com by adr_gonz...@yahoo.fr on 13 Feb 2013 at 5:04

GoogleCodeExporter commented 9 years ago
I've played with this idea some time ago as well and I decided that it's hard 
to keep it extensible and reusable for _everyone_ and that it's almost better 
to let everyone create its own.

Also, I'm not sure if a composite is the best choice for this construct as it 
get rendered as a single component which is thus not useable in e.g. a 
<h:panelGrid columns="3">. True, one could throw in some CSS, but this is more 
than often a hell lot of work with regard to pixel-precise positioning, 
aligning and text-wrapping in form labels, inputs and messages on a single row. 
A tag file is then preferred, see also e.g. 
http://stackoverflow.com/questions/5713718/how-to-make-a-grid-of-jsf-composite-c
omponent

Original comment by balusc on 13 Feb 2013 at 5:35

GoogleCodeExporter commented 9 years ago
Thanks for the answer balusc ! Nice link

Pity for me though ;)

Some remarks about the 2 approaches (but you surely know them) :
 1. UIInputContainer <quote>which is thus not useable in e.g. a <h:panelGrid columns="3"></quote>
   I always used div to display input in my real life projects (I throw Bootstrap CSS : http://twitter.github.com/bootstrap/base-css.html#forms, chapter Horizontal form), so I never stumble on this constraint.
 2. About http://stackoverflow.com/questions/5713718/how-to-make-a-grid-of-jsf-composite-component
    This approach seems to me more limited than UIInputContainer :
    With UIInputContainer, if I need to use a rich:calendar, I just do :
<field:edit id="nom" label="#{messages['chargeClientele.nom.label']}">
  <rich:calendar value="#{sampleController.value}"/>
</field:edit>
    With a tag file, I need to add a c:when in the tag file (and I'll end with a really huge one).
    Same thing if I need to use a h:inputText with a custom f:ajax, I'll need to modify the tag file for this need.

Original comment by adr_gonz...@yahoo.fr on 14 Feb 2013 at 9:35

GoogleCodeExporter commented 9 years ago
What if one doesn't use bootstrap and therefore needs something different than 
those <i class="icon-msg-err">, <div class="controls"> and <p 
class="help-block">? 

All with all, the idea is nice, I personally like it and have also used such a 
composite/tagfile in several projects. But they were never the same, nor could 
they be. Such a composite/tagfile in OmniFaces would not be usable to 
_everyone_. OmniFaces is aimed to be usable to _everyone_, based on top 
standard JSF. 

Perhaps you could consider creating a separate UI component library offering 
composites targeting on Bootstrap CSS.

Original comment by balusc on 15 Feb 2013 at 2:14

GoogleCodeExporter commented 9 years ago
Sorry balusc,

I think we didn't understand ourselves (I'm not an english speaker).
This issue was about including UIInputContainer, *not* the sample tagfile I've 
showed. The latter is of course project dependent.

Best regards,

Original comment by adr_gonz...@yahoo.fr on 15 Feb 2013 at 9:05

GoogleCodeExporter commented 9 years ago
Hmm, I think I didn't see how UIInputContainer is helpful. How exactly is it 
helpful for you? 

Original comment by balusc on 15 Feb 2013 at 11:55

GoogleCodeExporter commented 9 years ago
InputContainer scans its children to retrieve EditableValueHolder, UIMessage 
and HtmlOutputLabel component).

It then :
 * valorises invalid and required variables (invalid=true if there's at least a WARN message associated with the input component).
   This is handy in the tag file to add a CSS error class.
 * associates automatically h:message for attribute with the input id.
 * same thing for h:outputLabel for attribute.
I hope I didn't forget anything.

This makes it simple to write whatever tagfile for label/input/message trio.
With the limitation you raised : you cannot really use UIInputContainer with 
h:panelGrid.
Another one : I'm not sure UIInputContainer will be able to handle several 
input components (it's more for only one input at a time).

Sample code 
https://github.com/seam/faces/blob/develop/api/src/main/java/org/jboss/seam/face
s/component/UIInputContainer.java.

But be warned, this one has quite some bugs.

Original comment by adr_gonz...@yahoo.fr on 15 Feb 2013 at 12:14

GoogleCodeExporter commented 9 years ago
As Bauke mentioned, the idea is attractive and something we have attempted over 
the years but never got quite right into a re-useable solution.

Ultimately, I think that there should be an artifact in JSF that is a cross 
between tag files and composite components; the ease of use and 
auto-registration of a composite, but the "no-inserted-parent" behavior of a 
tag file. I created issue 
https://java.net/jira/browse/JAVASERVERFACES_SPEC_PUBLIC-1196 for this earlier.

One of the ideas that I explored back then but didn't pursue, was for a 
panelGrid component to be able to look into a given component for rendering its 
children. E.g.

<o:panelGrid traverseInto="bla" columns="3">

     <z:someComposite id="bla">
            <h:inputText id=… value=…
     </z:someComposite>

</o:panelGrid>

Where z:someComposite is a composite component containing 3 children in total. 
Of course this would be of limited use, since there's a ton of other components 
(like p:panelGrid, and the various data tables, etc) for which it still 
wouldn't work.

Another thing I had been thinking about was to pick up and re-insert children 
via a helper tag:

<h:panelGrid columns="3">

    <o:moveChildrenUp>
        <z:someComposite id="bla">
            <h:inputText id=… value=…
         </z:someComposite>
    </o:moveChildrenUp>

</h:panelGrid>

I never pursued this either since A) it's a bit verbose, negating the 
advantages of moving stuff into a composite component in the first place and B) 
composite components already do some moving around of components in the tree, 
and this has caused some bugs in the passed. I was and still am not 100% sure 
if this wouldn't open a new can of worms.

Still, this or a variant of it might be something to look into anyway. What do 
you guys think?

Original comment by arjan.tijms on 23 Oct 2013 at 4:09

GoogleCodeExporter commented 9 years ago
I'm still split whether to add this to OmniFaces or not as I personally 
prefer/recommend using a tagfile approach over a composite component approach 
for this particular purpose. I also find the Seam Faces implementation a bit 
clumsy, why not just finding the concrete UIInput component and returning it as 
#{cc.input}, so that you can in turn directly reference its standard attributes 
like #{cc.input.value}, #{cc.input.required}, etc?

Also, this issue has received no votes so far. In any way, feel free to reopen 
at GitHub.

Original comment by balusc on 17 Apr 2014 at 10:08

GoogleCodeExporter commented 9 years ago
And #{cc.input.valid} resp #{not cc.input.valid}.

Original comment by balusc on 17 Apr 2014 at 10:09