You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@myfaces.apache.org by Matt Raible <li...@raibledesigns.com> on 2004/12/02 03:33:37 UTC

h:outputLabel - validation and colons

Hello all,

I've been doing a bit of MyFaces development this week and enjoying it 
for the most part.  I have a couple questions about <h:outputLabel>:

1. Is there anyway to modify h:outputLabel to add an asterisk for 
required fields?  Do I have to subclass the existing JSP Tag to do 
this?
2. Is it possible to auto-add a colon?  I'm able to do this pretty 
easily with a custom taglib and Commons Validator, but it seems 
difficult with MyFaces?  With Tapestry, I can subclass the existing 
component and add my own suffix (including a space before the colon for 
the French locale).

Thanks,

Matt


Re: h:outputLabel - validation and colons

Posted by Craig McClanahan <cr...@gmail.com>.
On Wed, 1 Dec 2004 23:52:54 -0700, Matt Raible <li...@raibledesigns.com> wrote:
> Thanks David - much appreciated.  Unfortunately, in my testing the
> "input" is always null b/c the label comes before the component it's
> for.  If I move the label after the field, then the asterisk renders
> properly.  Am I missing something?

No, you're not :-(.  This is one of the interoperability issues
between JSF and JSP that we couldn't find a good solution for in a JSF
1.0 time frame.

The issue is that, on the *first* rendering of a page, the component
tree is built on the fly, in the order that the tags are evaluated. 
On a subsequent rendering of the same page, the component tree will
already be there, and the asterisk will work as expected; it's only
the first time that there is an issue.

Craig

> 
> Thanks,
> 
> Matt
> 
> 
> 
> David Geary wrote:
> 
> > Le Dec 1, 2004, à 9:42 PM, David Geary a écrit :
> >
> > [snip]
> >
> >>> Hmmm, sounds like I have to have a getter method for each form field
> >>> on my managed bean?  What a pain?
> >>>  Isn't there a way to look up if the field is required and just add
> >>> a * - a solution that's generic for all outputLabel's?  I'm willing
> >>> to hack source code or create components if I need to - I just need
> >>> to know 2 things:
> >>>
> >>> 1.  Yes/No - if I have to hack the source to make the dynamic lookup
> >>> possible?
> >>
> >>
> >> No hacking is required.
> >>
> >>> 2.  Where do I hack the source? I'm guessing there's some way to
> >>> lookup the validation metadata for the inputs and use that data in
> >>> the labels.
> >>
> >>
> >> You could implementing a replacement for the Label renderer:
> >>
> >> 1. In a renderer method such as encodeBegin(), get the value of the
> >> renderer's component (encodeBegin is passed the component. Call the
> >> component's getValue method). In this case, the component is the
> >> label and the value is the id of the labeled component.
> >>
> >> 2. Get a reference to the labeled component. In a JSF component
> >> hierarchy, any component can find any other component in the
> >> hierarchy with the findComponent(String) method, where the String is
> >> the component's id. So the label can find the labeled component.
> >>
> >> 3. Find out if the labeled component is required. Input components
> >> implement the editableValueHolder interface, which defines an
> >> isRequired method.
> >>
> >> 4. Render according to whether the labeled component is required.
> >>
> >>
> >> david
> >
> >
> > I went ahead and implemented this. After replacing the standard Label
> > renderer, this...
> >
> > <h:outputLabel for="name" value="#{msgs.namePrompt}"/>
> > <h:inputText id="name" value="#{registerForm.name}" />
> >
> > ...has a plain prompt, whereas the following has an asterik prepended
> > to the prompt:
> >
> > <h:outputLabel for="name" value="#{msgs.namePrompt}"/>
> > <h:inputText id="name" value="#{registerForm.name}" required="true"/>
> >
> > Here's how it works. First, add this to your faces config file:
> >
> > <faces-config>
> >    ...
> >    <render-kit>
> >       <description>Some replacements for the standard
> > renderers</description>
> >       <renderer>
> >          <description>Replacement renderer for
> > h:outputLabel</description>
> >          <component-family>javax.faces.Output</component-family>
> >          <renderer-type>javax.faces.Label</renderer-type>
> >          <renderer-class>renderers.LabelRenderer</renderer-class>
> >       </renderer>
> >    </render-kit>
> > </faces-config>
> >
> > Because we didn't specify a renderkit name, JSF modifies the default
> > renderkit by replacing the javax.faces.Label type renderer with our
> > custom version.
> >
> > Here's the renderer class:
> >
> > package renderers;
> >
> > import java.util.Map;
> > import javax.faces.component.UIComponent;
> > import javax.faces.component.UIInput;
> > import javax.faces.context.FacesContext;
> > import javax.faces.context.ResponseWriter;
> > import javax.faces.render.Renderer;
> >
> > // Renderer for the Label components
> >
> > public class LabelRenderer extends Renderer {
> >    public boolean getRendersChildren() {
> >       return false;
> >    }
> >
> >    public void encodeBegin(FacesContext context, UIComponent component)
> >          throws java.io.IOException {
> >       ResponseWriter writer = context.getResponseWriter();
> >       writer.startElement("label", component);
> >
> >       String styleClass = (String)
> > component.getAttributes().get("styleClass");
> >       if (styleClass != null)
> >          writer.writeAttribute("class", styleClass, null);
> >
> >       Map attrs = component.getAttributes();
> >       writer.writeAttribute("for", component.getClientId(context),
> > null);
> >
> >       UIInput input =
> > (UIInput)component.findComponent((String)attrs.get("for"));
> >       if(input.isRequired())
> >          writer.write("*");
> >
> >       writer.write(attrs.get("value").toString());
> >    }
> >
> >    public void encodeEnd(FacesContext context, UIComponent component)
> >          throws java.io.IOException {
> >       ResponseWriter writer = context.getResponseWriter();
> >       writer.endElement("label");
> >    }
> > }
> >
> > What's cool about this is that all h:outputLabel tags will be fitted
> > with our custom renderer, so by modifying the config file and
> > implementing the renderer, we are changing the behavior of existing
> > JSP pages without modifying the pages themselves. All labels that
> > decorate required fields will be prepended with asteriks.
> >
> > Notice that my simple renderer is not industrial strength. It does not
> > account for all the h:outputLabel attributes, nor does it allow a
> > nested component. But it's not too bad for 20 minutes of work.
> >
> > btw, it's easy to add an enhancement so that the asterik is red if the
> > corresponding field failed validation. Here's the modified encodeBegin
> > method of the renderer:
> >
> > ...
> > public void encodeBegin(FacesContext context, UIComponent component)
> >          throws java.io.IOException {
> >       ResponseWriter writer = context.getResponseWriter();
> >       writer.startElement("label", component);
> >
> >       String styleClass = (String)
> > component.getAttributes().get("styleClass");
> >       if (styleClass != null)
> >          writer.writeAttribute("class", styleClass, null);
> >
> >       Map attrs = component.getAttributes();
> >       writer.writeAttribute("for", component.getClientId(context),
> > null);
> >
> >       UIInput input =
> > (UIInput)component.findComponent((String)attrs.get("for"));
> >       if(input.isRequired()) {
> >          boolean msgs = hasMessages(context, input);
> >          if(msgs) {
> >             writer.startElement("font", null);
> >             writer.writeAttribute("color", "red", null);
> >          }
> >          writer.write("*");
> >          if(msgs) {
> >             writer.endElement("font");
> >          }
> >       }
> >       writer.write(attrs.get("value").toString());
> >    }
> >
> >    private boolean hasMessages(FacesContext context, UIComponent
> > component) {
> >       Iterator it = context.getClientIdsWithMessages();
> >       boolean found = false;
> >
> >       while(it.hasNext()) {
> >          String id = (String)it.next();
> >          if(component.getClientId(context).equals(id))
> >             found = true;
> >       }
> >       return found;
> >    }
> > ...
> >
> > david
> >
> >>
> >>>
> >>> Thanks,
> >>>
> >>> Matt
> >>>
> >>>>
> >>>>> Do I have to subclass the existing JSP Tag to do this?
> >>>>
> >>>>
> >>>> You hardly ever want to subclass an existing component tag, because
> >>>> tags are really just thin veneers for component/renderer pairs. You
> >>>> could, however, implement your own Label renderer and plug it into
> >>>> h:outputLabel. But I would opt for one of the easier solutions
> >>>> above.
> >>>>
> >>>>> 2. Is it possible to auto-add a colon?  I'm able to do this pretty
> >>>>> easily with a custom taglib and Commons Validator, but it seems
> >>>>> difficult with MyFaces?  With Tapestry, I can subclass the
> >>>>> existing component and add my own suffix (including a space before
> >>>>> the colon for the French locale).
> >>>>
> >>>>
> >>>> The same techniques for prepending an asterik will work for
> >>>> appending a colon. Again, you could implement your own Label
> >>>> renderer that does anything you want.
> >>>>
> >>>>
> >>>> david
> >>>>
> >>>>>
> >>>>> Thanks,
> >>>>>
> >>>>> Matt
> >>>>>
> >>>>
> >>>
> >>
> >
> 
>

Re: h:outputLabel - validation and colons

Posted by Matt Raible <li...@raibledesigns.com>.
Thanks - this did the trick.

Matt

Martin Marinschek wrote:

> this is due to the JSP model that is the underlying component
> structure definition - what you need to do is include the fields into
> an h:panelGroup (will render as a span) or a h:panelGrid or something
> like that - you need to have a faces tag around your label and input
> components.
>
> HTH,
>
> Martin
>
> example:
>
>    <h:panelGrid columns="3" styleClass="grid" headerClass="gridHeader">
>        <h:outputLabel styleClass="label jsf_description"
> for="creationOfMetadata" value="Erstellungsdatum der
> Content-Metainformationen"/>
>        <h:inputText id="creationOfMetadata"
> value="#{metadataNewDetailForm.metadataIdentification.creationOfMetadat 
> a}"
> required="true"/>
>        <x:message for="creationOfMetadata"
> detailFormat="#{messagesBundleMap['detailMessage']}"/>
>        <h:outputLabel styleClass="label jsf_description"
> for="lastModificationOfMetadata" value="Letztes Änderungsdatum der
> Content-Metainformationen" />
>        <h:inputText id="lastModificationOfMetadata"
> value="#{metadataNewDetailForm.metadataIdentification.lastModificationO 
> fMetadata}"
> required="true"/>
>        <x:message for="lastModificationOfMetadata"
> detailFormat="#{messagesBundleMap['detailMessage']}"/>
>
>        <h:outputLabel styleClass="label jsf_description"
> for="creationOfData" value="Erstellungsdatum des Contents"/>
>        <h:inputText id="creationOfData"
> value="#{metadataNewDetailForm.metadataIdentification.creationOfData}"
> required="true"/>
>        <x:message for="creationOfData"
> detailFormat="#{messagesBundleMap['detailMessage']}"/>
>        <h:outputLabel styleClass="label jsf_description"
> for="lastModificationOfData" value="Letztes Änderungsdatum des
> Contents" />
>        <h:inputText id="lastModificationOfData"
> value="#{metadataNewDetailForm.metadataIdentification.lastModificationO 
> fData}"
> required="true"/>
>        <x:message for="lastModificationOfData"
> detailFormat="#{messagesBundleMap['detailMessage']}"/>
>
>    </h:panelGrid>
>
>
> On Wed, 1 Dec 2004 23:52:54 -0700, Matt Raible  
> <li...@raibledesigns.com> wrote:
>
>> Thanks David - much appreciated.  Unfortunately, in my testing the
>> "input" is always null b/c the label comes before the component it's
>> for.  If I move the label after the field, then the asterisk renders
>> properly.  Am I missing something?
>>
>> Thanks,
>>
>> Matt
>>
>>
>>
>> David Geary wrote:
>>
>>
>>> Le Dec 1, 2004, à 9:42 PM, David Geary a écrit :
>>>
>>> [snip]
>>>
>>>
>>>>> Hmmm, sounds like I have to have a getter method for each form  
>>>>> field
>>>>> on my managed bean?  What a pain?
>>>>> Isn't there a way to look up if the field is required and just add
>>>>> a * - a solution that's generic for all outputLabel's?  I'm willing
>>>>> to hack source code or create components if I need to - I just need
>>>>> to know 2 things:
>>>>>
>>>>> 1.  Yes/No - if I have to hack the source to make the dynamic  
>>>>> lookup
>>>>> possible?
>>>>>
>>>> No hacking is required.
>>>>
>>>>
>>>>> 2.  Where do I hack the source? I'm guessing there's some way to
>>>>> lookup the validation metadata for the inputs and use that data in
>>>>> the labels.
>>>>>
>>>> You could implementing a replacement for the Label renderer:
>>>>
>>>> 1. In a renderer method such as encodeBegin(), get the value of the
>>>> renderer's component (encodeBegin is passed the component. Call the
>>>> component's getValue method). In this case, the component is the
>>>> label and the value is the id of the labeled component.
>>>>
>>>> 2. Get a reference to the labeled component. In a JSF component
>>>> hierarchy, any component can find any other component in the
>>>> hierarchy with the findComponent(String) method, where the String is
>>>> the component's id. So the label can find the labeled component.
>>>>
>>>> 3. Find out if the labeled component is required. Input components
>>>> implement the editableValueHolder interface, which defines an
>>>> isRequired method.
>>>>
>>>> 4. Render according to whether the labeled component is required.
>>>>
>>>>
>>>> david
>>>>
>>> I went ahead and implemented this. After replacing the standard Label
>>> renderer, this...
>>>
>>> <h:outputLabel for="name" value="#{msgs.namePrompt}"/>
>>> <h:inputText id="name" value="#{registerForm.name}" />
>>>
>>> ...has a plain prompt, whereas the following has an asterik prepended
>>> to the prompt:
>>>
>>> <h:outputLabel for="name" value="#{msgs.namePrompt}"/>
>>> <h:inputText id="name" value="#{registerForm.name}" required="true"/>
>>>
>>> Here's how it works. First, add this to your faces config file:
>>>
>>> <faces-config>
>>>   ...
>>>   <render-kit>
>>>      <description>Some replacements for the standard
>>> renderers</description>
>>>      <renderer>
>>>         <description>Replacement renderer for
>>> h:outputLabel</description>
>>>         <component-family>javax.faces.Output</component-family>
>>>         <renderer-type>javax.faces.Label</renderer-type>
>>>         <renderer-class>renderers.LabelRenderer</renderer-class>
>>>      </renderer>
>>>   </render-kit>
>>> </faces-config>
>>>
>>> Because we didn't specify a renderkit name, JSF modifies the default
>>> renderkit by replacing the javax.faces.Label type renderer with our
>>> custom version.
>>>
>>> Here's the renderer class:
>>>
>>> package renderers;
>>>
>>> import java.util.Map;
>>> import javax.faces.component.UIComponent;
>>> import javax.faces.component.UIInput;
>>> import javax.faces.context.FacesContext;
>>> import javax.faces.context.ResponseWriter;
>>> import javax.faces.render.Renderer;
>>>
>>> // Renderer for the Label components
>>>
>>> public class LabelRenderer extends Renderer {
>>>   public boolean getRendersChildren() {
>>>      return false;
>>>   }
>>>
>>>   public void encodeBegin(FacesContext context, UIComponent  
>>> component)
>>>         throws java.io.IOException {
>>>      ResponseWriter writer = context.getResponseWriter();
>>>      writer.startElement("label", component);
>>>
>>>      String styleClass = (String)
>>> component.getAttributes().get("styleClass");
>>>      if (styleClass != null)
>>>         writer.writeAttribute("class", styleClass, null);
>>>
>>>      Map attrs = component.getAttributes();
>>>      writer.writeAttribute("for", component.getClientId(context),
>>> null);
>>>
>>>      UIInput input =
>>> (UIInput)component.findComponent((String)attrs.get("for"));
>>>      if(input.isRequired())
>>>         writer.write("*");
>>>
>>>      writer.write(attrs.get("value").toString());
>>>   }
>>>
>>>   public void encodeEnd(FacesContext context, UIComponent component)
>>>         throws java.io.IOException {
>>>      ResponseWriter writer = context.getResponseWriter();
>>>      writer.endElement("label");
>>>   }
>>> }
>>>
>>> What's cool about this is that all h:outputLabel tags will be fitted
>>> with our custom renderer, so by modifying the config file and
>>> implementing the renderer, we are changing the behavior of existing
>>> JSP pages without modifying the pages themselves. All labels that
>>> decorate required fields will be prepended with asteriks.
>>>
>>> Notice that my simple renderer is not industrial strength. It does  
>>> not
>>> account for all the h:outputLabel attributes, nor does it allow a
>>> nested component. But it's not too bad for 20 minutes of work.
>>>
>>> btw, it's easy to add an enhancement so that the asterik is red if  
>>> the
>>> corresponding field failed validation. Here's the modified  
>>> encodeBegin
>>> method of the renderer:
>>>
>>> ...
>>> public void encodeBegin(FacesContext context, UIComponent component)
>>>         throws java.io.IOException {
>>>      ResponseWriter writer = context.getResponseWriter();
>>>      writer.startElement("label", component);
>>>
>>>      String styleClass = (String)
>>> component.getAttributes().get("styleClass");
>>>      if (styleClass != null)
>>>         writer.writeAttribute("class", styleClass, null);
>>>
>>>      Map attrs = component.getAttributes();
>>>      writer.writeAttribute("for", component.getClientId(context),
>>> null);
>>>
>>>      UIInput input =
>>> (UIInput)component.findComponent((String)attrs.get("for"));
>>>      if(input.isRequired()) {
>>>         boolean msgs = hasMessages(context, input);
>>>         if(msgs) {
>>>            writer.startElement("font", null);
>>>            writer.writeAttribute("color", "red", null);
>>>         }
>>>         writer.write("*");
>>>         if(msgs) {
>>>            writer.endElement("font");
>>>         }
>>>      }
>>>      writer.write(attrs.get("value").toString());
>>>   }
>>>
>>>   private boolean hasMessages(FacesContext context, UIComponent
>>> component) {
>>>      Iterator it = context.getClientIdsWithMessages();
>>>      boolean found = false;
>>>
>>>      while(it.hasNext()) {
>>>         String id = (String)it.next();
>>>         if(component.getClientId(context).equals(id))
>>>            found = true;
>>>      }
>>>      return found;
>>>   }
>>> ...
>>>
>>> david
>>>
>>>
>>>>> Thanks,
>>>>>
>>>>> Matt
>>>>>
>>>>>
>>>>>>> Do I have to subclass the existing JSP Tag to do this?
>>>>>>>
>>>>>> You hardly ever want to subclass an existing component tag,  
>>>>>> because
>>>>>> tags are really just thin veneers for component/renderer pairs.  
>>>>>> You
>>>>>> could, however, implement your own Label renderer and plug it into
>>>>>> h:outputLabel. But I would opt for one of the easier solutions
>>>>>> above.
>>>>>>
>>>>>>
>>>>>>> 2. Is it possible to auto-add a colon?  I'm able to do this  
>>>>>>> pretty
>>>>>>> easily with a custom taglib and Commons Validator, but it seems
>>>>>>> difficult with MyFaces?  With Tapestry, I can subclass the
>>>>>>> existing component and add my own suffix (including a space  
>>>>>>> before
>>>>>>> the colon for the French locale).
>>>>>>>
>>>>>> The same techniques for prepending an asterik will work for
>>>>>> appending a colon. Again, you could implement your own Label
>>>>>> renderer that does anything you want.
>>>>>>
>>>>>>
>>>>>> david
>>>>>>
>>>>>>
>>>>>>> Thanks,
>>>>>>>
>>>>>>> Matt
>>>>>>>
>>>>>>>
>>



Re: h:outputLabel - validation and colons

Posted by Martin Marinschek <ma...@gmail.com>.
this is due to the JSP model that is the underlying component
structure definition - what you need to do is include the fields into
an h:panelGroup (will render as a span) or a h:panelGrid or something
like that - you need to have a faces tag around your label and input
components.

HTH,

Martin

example:

    <h:panelGrid columns="3" styleClass="grid" headerClass="gridHeader">
        <h:outputLabel styleClass="label jsf_description"
for="creationOfMetadata" value="Erstellungsdatum der
Content-Metainformationen"/>
        <h:inputText id="creationOfMetadata"
value="#{metadataNewDetailForm.metadataIdentification.creationOfMetadata}"
required="true"/>
        <x:message for="creationOfMetadata"
detailFormat="#{messagesBundleMap['detailMessage']}"/>
        <h:outputLabel styleClass="label jsf_description"
for="lastModificationOfMetadata" value="Letztes Änderungsdatum der
Content-Metainformationen" />
        <h:inputText id="lastModificationOfMetadata"
value="#{metadataNewDetailForm.metadataIdentification.lastModificationOfMetadata}"
required="true"/>
        <x:message for="lastModificationOfMetadata"
detailFormat="#{messagesBundleMap['detailMessage']}"/>

        <h:outputLabel styleClass="label jsf_description"
for="creationOfData" value="Erstellungsdatum des Contents"/>
        <h:inputText id="creationOfData"
value="#{metadataNewDetailForm.metadataIdentification.creationOfData}"
required="true"/>
        <x:message for="creationOfData"
detailFormat="#{messagesBundleMap['detailMessage']}"/>
        <h:outputLabel styleClass="label jsf_description"
for="lastModificationOfData" value="Letztes Änderungsdatum des
Contents" />
        <h:inputText id="lastModificationOfData"
value="#{metadataNewDetailForm.metadataIdentification.lastModificationOfData}"
required="true"/>
        <x:message for="lastModificationOfData"
detailFormat="#{messagesBundleMap['detailMessage']}"/>

    </h:panelGrid>


On Wed, 1 Dec 2004 23:52:54 -0700, Matt Raible <li...@raibledesigns.com> wrote:
> Thanks David - much appreciated.  Unfortunately, in my testing the
> "input" is always null b/c the label comes before the component it's
> for.  If I move the label after the field, then the asterisk renders
> properly.  Am I missing something?
> 
> Thanks,
> 
> Matt
> 
> 
> 
> David Geary wrote:
> 
> > Le Dec 1, 2004, à 9:42 PM, David Geary a écrit :
> >
> > [snip]
> >
> >>> Hmmm, sounds like I have to have a getter method for each form field
> >>> on my managed bean?  What a pain?
> >>>  Isn't there a way to look up if the field is required and just add
> >>> a * - a solution that's generic for all outputLabel's?  I'm willing
> >>> to hack source code or create components if I need to - I just need
> >>> to know 2 things:
> >>>
> >>> 1.  Yes/No - if I have to hack the source to make the dynamic lookup
> >>> possible?
> >>
> >>
> >> No hacking is required.
> >>
> >>> 2.  Where do I hack the source? I'm guessing there's some way to
> >>> lookup the validation metadata for the inputs and use that data in
> >>> the labels.
> >>
> >>
> >> You could implementing a replacement for the Label renderer:
> >>
> >> 1. In a renderer method such as encodeBegin(), get the value of the
> >> renderer's component (encodeBegin is passed the component. Call the
> >> component's getValue method). In this case, the component is the
> >> label and the value is the id of the labeled component.
> >>
> >> 2. Get a reference to the labeled component. In a JSF component
> >> hierarchy, any component can find any other component in the
> >> hierarchy with the findComponent(String) method, where the String is
> >> the component's id. So the label can find the labeled component.
> >>
> >> 3. Find out if the labeled component is required. Input components
> >> implement the editableValueHolder interface, which defines an
> >> isRequired method.
> >>
> >> 4. Render according to whether the labeled component is required.
> >>
> >>
> >> david
> >
> >
> > I went ahead and implemented this. After replacing the standard Label
> > renderer, this...
> >
> > <h:outputLabel for="name" value="#{msgs.namePrompt}"/>
> > <h:inputText id="name" value="#{registerForm.name}" />
> >
> > ...has a plain prompt, whereas the following has an asterik prepended
> > to the prompt:
> >
> > <h:outputLabel for="name" value="#{msgs.namePrompt}"/>
> > <h:inputText id="name" value="#{registerForm.name}" required="true"/>
> >
> > Here's how it works. First, add this to your faces config file:
> >
> > <faces-config>
> >    ...
> >    <render-kit>
> >       <description>Some replacements for the standard
> > renderers</description>
> >       <renderer>
> >          <description>Replacement renderer for
> > h:outputLabel</description>
> >          <component-family>javax.faces.Output</component-family>
> >          <renderer-type>javax.faces.Label</renderer-type>
> >          <renderer-class>renderers.LabelRenderer</renderer-class>
> >       </renderer>
> >    </render-kit>
> > </faces-config>
> >
> > Because we didn't specify a renderkit name, JSF modifies the default
> > renderkit by replacing the javax.faces.Label type renderer with our
> > custom version.
> >
> > Here's the renderer class:
> >
> > package renderers;
> >
> > import java.util.Map;
> > import javax.faces.component.UIComponent;
> > import javax.faces.component.UIInput;
> > import javax.faces.context.FacesContext;
> > import javax.faces.context.ResponseWriter;
> > import javax.faces.render.Renderer;
> >
> > // Renderer for the Label components
> >
> > public class LabelRenderer extends Renderer {
> >    public boolean getRendersChildren() {
> >       return false;
> >    }
> >
> >    public void encodeBegin(FacesContext context, UIComponent component)
> >          throws java.io.IOException {
> >       ResponseWriter writer = context.getResponseWriter();
> >       writer.startElement("label", component);
> >
> >       String styleClass = (String)
> > component.getAttributes().get("styleClass");
> >       if (styleClass != null)
> >          writer.writeAttribute("class", styleClass, null);
> >
> >       Map attrs = component.getAttributes();
> >       writer.writeAttribute("for", component.getClientId(context),
> > null);
> >
> >       UIInput input =
> > (UIInput)component.findComponent((String)attrs.get("for"));
> >       if(input.isRequired())
> >          writer.write("*");
> >
> >       writer.write(attrs.get("value").toString());
> >    }
> >
> >    public void encodeEnd(FacesContext context, UIComponent component)
> >          throws java.io.IOException {
> >       ResponseWriter writer = context.getResponseWriter();
> >       writer.endElement("label");
> >    }
> > }
> >
> > What's cool about this is that all h:outputLabel tags will be fitted
> > with our custom renderer, so by modifying the config file and
> > implementing the renderer, we are changing the behavior of existing
> > JSP pages without modifying the pages themselves. All labels that
> > decorate required fields will be prepended with asteriks.
> >
> > Notice that my simple renderer is not industrial strength. It does not
> > account for all the h:outputLabel attributes, nor does it allow a
> > nested component. But it's not too bad for 20 minutes of work.
> >
> > btw, it's easy to add an enhancement so that the asterik is red if the
> > corresponding field failed validation. Here's the modified encodeBegin
> > method of the renderer:
> >
> > ...
> > public void encodeBegin(FacesContext context, UIComponent component)
> >          throws java.io.IOException {
> >       ResponseWriter writer = context.getResponseWriter();
> >       writer.startElement("label", component);
> >
> >       String styleClass = (String)
> > component.getAttributes().get("styleClass");
> >       if (styleClass != null)
> >          writer.writeAttribute("class", styleClass, null);
> >
> >       Map attrs = component.getAttributes();
> >       writer.writeAttribute("for", component.getClientId(context),
> > null);
> >
> >       UIInput input =
> > (UIInput)component.findComponent((String)attrs.get("for"));
> >       if(input.isRequired()) {
> >          boolean msgs = hasMessages(context, input);
> >          if(msgs) {
> >             writer.startElement("font", null);
> >             writer.writeAttribute("color", "red", null);
> >          }
> >          writer.write("*");
> >          if(msgs) {
> >             writer.endElement("font");
> >          }
> >       }
> >       writer.write(attrs.get("value").toString());
> >    }
> >
> >    private boolean hasMessages(FacesContext context, UIComponent
> > component) {
> >       Iterator it = context.getClientIdsWithMessages();
> >       boolean found = false;
> >
> >       while(it.hasNext()) {
> >          String id = (String)it.next();
> >          if(component.getClientId(context).equals(id))
> >             found = true;
> >       }
> >       return found;
> >    }
> > ...
> >
> > david
> >
> >>
> >>>
> >>> Thanks,
> >>>
> >>> Matt
> >>>
> >>>>
> >>>>> Do I have to subclass the existing JSP Tag to do this?
> >>>>
> >>>>
> >>>> You hardly ever want to subclass an existing component tag, because
> >>>> tags are really just thin veneers for component/renderer pairs. You
> >>>> could, however, implement your own Label renderer and plug it into
> >>>> h:outputLabel. But I would opt for one of the easier solutions
> >>>> above.
> >>>>
> >>>>> 2. Is it possible to auto-add a colon?  I'm able to do this pretty
> >>>>> easily with a custom taglib and Commons Validator, but it seems
> >>>>> difficult with MyFaces?  With Tapestry, I can subclass the
> >>>>> existing component and add my own suffix (including a space before
> >>>>> the colon for the French locale).
> >>>>
> >>>>
> >>>> The same techniques for prepending an asterik will work for
> >>>> appending a colon. Again, you could implement your own Label
> >>>> renderer that does anything you want.
> >>>>
> >>>>
> >>>> david
> >>>>
> >>>>>
> >>>>> Thanks,
> >>>>>
> >>>>> Matt
> >>>>>
> >>>>
> >>>
> >>
> >
> 
>

RE: h:outputLabel - validation and colons

Posted by Matthias Wessendorf <ma...@matthias-wessendorf.de>.
Matt,

Craig, Martin and Jesse told you
some workarounds to your problems.

In this article Hans Bergsten
wrote about JSP *and* JSF.
http://www.onjava.com/pub/a/onjava/2004/06/09/jsf.html

Perhaps it is usful for you to read it.


Nice day,
Matthias 

> -----Original Message-----
> From: Matt Raible [mailto:lists@raibledesigns.com] 
> Sent: Thursday, December 02, 2004 7:53 AM
> To: MyFaces Discussion
> Subject: Re: h:outputLabel - validation and colons
> 
> 
> Thanks David - much appreciated.  Unfortunately, in my testing the 
> "input" is always null b/c the label comes before the component it's 
> for.  If I move the label after the field, then the asterisk renders 
> properly.  Am I missing something?
> 
> Thanks,
> 
> Matt
> 
> David Geary wrote:
> 
> > Le Dec 1, 2004, à 9:42 PM, David Geary a écrit :
> >
> > [snip]
> >
> >>> Hmmm, sounds like I have to have a getter method for each 
> form field
> >>> on my managed bean?  What a pain?
> >>>  Isn't there a way to look up if the field is required 
> and just add 
> >>> a * - a solution that's generic for all outputLabel's?  
> I'm willing 
> >>> to hack source code or create components if I need to - I 
> just need 
> >>> to know 2 things:
> >>>
> >>> 1.  Yes/No - if I have to hack the source to make the 
> dynamic lookup
> >>> possible?
> >>
> >>
> >> No hacking is required.
> >>
> >>> 2.  Where do I hack the source? I'm guessing there's some way to
> >>> lookup the validation metadata for the inputs and use 
> that data in 
> >>> the labels.
> >>
> >>
> >> You could implementing a replacement for the Label renderer:
> >>
> >> 1. In a renderer method such as encodeBegin(), get the value of the
> >> renderer's component (encodeBegin is passed the component. 
> Call the 
> >> component's getValue method). In this case, the component is the 
> >> label and the value is the id of the labeled component.
> >>
> >> 2. Get a reference to the labeled component. In a JSF component
> >> hierarchy, any component can find any other component in the 
> >> hierarchy with the findComponent(String) method, where the 
> String is 
> >> the component's id. So the label can find the labeled component.
> >>
> >> 3. Find out if the labeled component is required. Input components
> >> implement the editableValueHolder interface, which defines an 
> >> isRequired method.
> >>
> >> 4. Render according to whether the labeled component is required.
> >>
> >>
> >> david
> >
> >
> > I went ahead and implemented this. After replacing the 
> standard Label
> > renderer, this...
> >
> > <h:outputLabel for="name" value="#{msgs.namePrompt}"/> <h:inputText 
> > id="name" value="#{registerForm.name}" />
> >
> > ...has a plain prompt, whereas the following has an asterik 
> prepended
> > to the prompt:
> >
> > <h:outputLabel for="name" value="#{msgs.namePrompt}"/> <h:inputText 
> > id="name" value="#{registerForm.name}" required="true"/>
> >
> > Here's how it works. First, add this to your faces config file:
> >
> > <faces-config>
> >    ...
> >    <render-kit>
> >       <description>Some replacements for the standard
> > renderers</description>
> >       <renderer>
> >          <description>Replacement renderer for 
> > h:outputLabel</description>
> >          <component-family>javax.faces.Output</component-family>
> >          <renderer-type>javax.faces.Label</renderer-type>
> >          <renderer-class>renderers.LabelRenderer</renderer-class>
> >       </renderer>
> >    </render-kit>
> > </faces-config>
> >
> > Because we didn't specify a renderkit name, JSF modifies the default
> > renderkit by replacing the javax.faces.Label type renderer with our 
> > custom version.
> >
> > Here's the renderer class:
> >
> > package renderers;
> >
> > import java.util.Map;
> > import javax.faces.component.UIComponent;
> > import javax.faces.component.UIInput;
> > import javax.faces.context.FacesContext;
> > import javax.faces.context.ResponseWriter;
> > import javax.faces.render.Renderer;
> >
> > // Renderer for the Label components
> >
> > public class LabelRenderer extends Renderer {
> >    public boolean getRendersChildren() {
> >       return false;
> >    }
> >
> >    public void encodeBegin(FacesContext context, 
> UIComponent component)
> >          throws java.io.IOException {
> >       ResponseWriter writer = context.getResponseWriter();
> >       writer.startElement("label", component);
> >
> >       String styleClass = (String)
> > component.getAttributes().get("styleClass");
> >       if (styleClass != null)
> >          writer.writeAttribute("class", styleClass, null);
> >
> >       Map attrs = component.getAttributes();
> >       writer.writeAttribute("for", component.getClientId(context),
> > null);
> >
> >       UIInput input =
> > (UIInput)component.findComponent((String)attrs.get("for"));
> >       if(input.isRequired())
> >          writer.write("*");
> >
> >       writer.write(attrs.get("value").toString());
> >    }
> >
> >    public void encodeEnd(FacesContext context, UIComponent 
> component)
> >          throws java.io.IOException {
> >       ResponseWriter writer = context.getResponseWriter();
> >       writer.endElement("label");
> >    }
> > }
> >
> > What's cool about this is that all h:outputLabel tags will be fitted
> > with our custom renderer, so by modifying the config file and 
> > implementing the renderer, we are changing the behavior of existing 
> > JSP pages without modifying the pages themselves. All labels that 
> > decorate required fields will be prepended with asteriks.
> >
> > Notice that my simple renderer is not industrial strength. 
> It does not
> > account for all the h:outputLabel attributes, nor does it allow a 
> > nested component. But it's not too bad for 20 minutes of work.
> >
> > btw, it's easy to add an enhancement so that the asterik is 
> red if the
> > corresponding field failed validation. Here's the modified 
> encodeBegin 
> > method of the renderer:
> >
> > ...
> > public void encodeBegin(FacesContext context, UIComponent component)
> >          throws java.io.IOException {
> >       ResponseWriter writer = context.getResponseWriter();
> >       writer.startElement("label", component);
> >
> >       String styleClass = (String)
> > component.getAttributes().get("styleClass");
> >       if (styleClass != null)
> >          writer.writeAttribute("class", styleClass, null);
> >
> >       Map attrs = component.getAttributes();
> >       writer.writeAttribute("for", component.getClientId(context),
> > null);
> >
> >       UIInput input =
> > (UIInput)component.findComponent((String)attrs.get("for"));
> >       if(input.isRequired()) {
> >          boolean msgs = hasMessages(context, input);
> >          if(msgs) {
> >             writer.startElement("font", null);
> >             writer.writeAttribute("color", "red", null);
> >          }
> >          writer.write("*");
> >          if(msgs) {
> >             writer.endElement("font");
> >          }
> >       }
> >       writer.write(attrs.get("value").toString());
> >    }
> >
> >    private boolean hasMessages(FacesContext context, UIComponent
> > component) {
> >       Iterator it = context.getClientIdsWithMessages();
> >       boolean found = false;
> >
> >       while(it.hasNext()) {
> >          String id = (String)it.next();
> >          if(component.getClientId(context).equals(id))
> >             found = true;
> >       }
> >       return found;
> >    }
> > ...
> >
> > david
> >
> >>
> >>>
> >>> Thanks,
> >>>
> >>> Matt
> >>>
> >>>>
> >>>>> Do I have to subclass the existing JSP Tag to do this?
> >>>>
> >>>>
> >>>> You hardly ever want to subclass an existing component 
> tag, because
> >>>> tags are really just thin veneers for component/renderer 
> pairs. You 
> >>>> could, however, implement your own Label renderer and 
> plug it into 
> >>>> h:outputLabel. But I would opt for one of the easier solutions 
> >>>> above.
> >>>>
> >>>>> 2. Is it possible to auto-add a colon?  I'm able to do 
> this pretty
> >>>>> easily with a custom taglib and Commons Validator, but it seems 
> >>>>> difficult with MyFaces?  With Tapestry, I can subclass the 
> >>>>> existing component and add my own suffix (including a 
> space before 
> >>>>> the colon for the French locale).
> >>>>
> >>>>
> >>>> The same techniques for prepending an asterik will work for
> >>>> appending a colon. Again, you could implement your own Label 
> >>>> renderer that does anything you want.
> >>>>
> >>>>
> >>>> david
> >>>>
> >>>>>
> >>>>> Thanks,
> >>>>>
> >>>>> Matt
> >>>>>
> >>>>
> >>>
> >>
> >
> 
> 


Re: h:outputLabel - validation and colons

Posted by Matt Raible <li...@raibledesigns.com>.
Thanks David - much appreciated.  Unfortunately, in my testing the 
"input" is always null b/c the label comes before the component it's 
for.  If I move the label after the field, then the asterisk renders 
properly.  Am I missing something?

Thanks,

Matt

David Geary wrote:

> Le Dec 1, 2004, à 9:42 PM, David Geary a écrit :
>
> [snip]
>
>>> Hmmm, sounds like I have to have a getter method for each form field 
>>> on my managed bean?  What a pain?
>>>  Isn't there a way to look up if the field is required and just add 
>>> a * - a solution that's generic for all outputLabel's?  I'm willing 
>>> to hack source code or create components if I need to - I just need 
>>> to know 2 things:
>>>
>>> 1.  Yes/No - if I have to hack the source to make the dynamic lookup 
>>> possible?
>>
>>
>> No hacking is required.
>>
>>> 2.  Where do I hack the source? I'm guessing there's some way to 
>>> lookup the validation metadata for the inputs and use that data in 
>>> the labels.
>>
>>
>> You could implementing a replacement for the Label renderer:
>>
>> 1. In a renderer method such as encodeBegin(), get the value of the 
>> renderer's component (encodeBegin is passed the component. Call the 
>> component's getValue method). In this case, the component is the 
>> label and the value is the id of the labeled component.
>>
>> 2. Get a reference to the labeled component. In a JSF component 
>> hierarchy, any component can find any other component in the 
>> hierarchy with the findComponent(String) method, where the String is 
>> the component's id. So the label can find the labeled component.
>>
>> 3. Find out if the labeled component is required. Input components 
>> implement the editableValueHolder interface, which defines an 
>> isRequired method.
>>
>> 4. Render according to whether the labeled component is required.
>>
>>
>> david
>
>
> I went ahead and implemented this. After replacing the standard Label 
> renderer, this...
>
> <h:outputLabel for="name" value="#{msgs.namePrompt}"/>
> <h:inputText id="name" value="#{registerForm.name}" />
>
> ...has a plain prompt, whereas the following has an asterik prepended 
> to the prompt:
>
> <h:outputLabel for="name" value="#{msgs.namePrompt}"/>
> <h:inputText id="name" value="#{registerForm.name}" required="true"/>
>
> Here's how it works. First, add this to your faces config file:
>
> <faces-config>
>    ...
>    <render-kit>
>       <description>Some replacements for the standard 
> renderers</description>
>       <renderer>
>          <description>Replacement renderer for 
> h:outputLabel</description>
>          <component-family>javax.faces.Output</component-family>
>          <renderer-type>javax.faces.Label</renderer-type>
>          <renderer-class>renderers.LabelRenderer</renderer-class>
>       </renderer>
>    </render-kit>
> </faces-config>
>
> Because we didn't specify a renderkit name, JSF modifies the default 
> renderkit by replacing the javax.faces.Label type renderer with our 
> custom version.
>
> Here's the renderer class:
>
> package renderers;
>
> import java.util.Map;
> import javax.faces.component.UIComponent;
> import javax.faces.component.UIInput;
> import javax.faces.context.FacesContext;
> import javax.faces.context.ResponseWriter;
> import javax.faces.render.Renderer;
>
> // Renderer for the Label components
>
> public class LabelRenderer extends Renderer {
>    public boolean getRendersChildren() {
>       return false;
>    }
>
>    public void encodeBegin(FacesContext context, UIComponent component)
>          throws java.io.IOException {
>       ResponseWriter writer = context.getResponseWriter();
>       writer.startElement("label", component);
>
>       String styleClass = (String) 
> component.getAttributes().get("styleClass");
>       if (styleClass != null)
>          writer.writeAttribute("class", styleClass, null);
>
>       Map attrs = component.getAttributes();
>       writer.writeAttribute("for", component.getClientId(context), 
> null);
>
>       UIInput input = 
> (UIInput)component.findComponent((String)attrs.get("for"));
>       if(input.isRequired())
>          writer.write("*");
>
>       writer.write(attrs.get("value").toString());
>    }
>
>    public void encodeEnd(FacesContext context, UIComponent component)
>          throws java.io.IOException {
>       ResponseWriter writer = context.getResponseWriter();
>       writer.endElement("label");
>    }
> }
>
> What's cool about this is that all h:outputLabel tags will be fitted 
> with our custom renderer, so by modifying the config file and 
> implementing the renderer, we are changing the behavior of existing 
> JSP pages without modifying the pages themselves. All labels that 
> decorate required fields will be prepended with asteriks.
>
> Notice that my simple renderer is not industrial strength. It does not 
> account for all the h:outputLabel attributes, nor does it allow a 
> nested component. But it's not too bad for 20 minutes of work.
>
> btw, it's easy to add an enhancement so that the asterik is red if the 
> corresponding field failed validation. Here's the modified encodeBegin 
> method of the renderer:
>
> ...
> public void encodeBegin(FacesContext context, UIComponent component)
>          throws java.io.IOException {
>       ResponseWriter writer = context.getResponseWriter();
>       writer.startElement("label", component);
>
>       String styleClass = (String) 
> component.getAttributes().get("styleClass");
>       if (styleClass != null)
>          writer.writeAttribute("class", styleClass, null);
>
>       Map attrs = component.getAttributes();
>       writer.writeAttribute("for", component.getClientId(context), 
> null);
>
>       UIInput input = 
> (UIInput)component.findComponent((String)attrs.get("for"));
>       if(input.isRequired()) {
>          boolean msgs = hasMessages(context, input);
>          if(msgs) {
>             writer.startElement("font", null);
>             writer.writeAttribute("color", "red", null);
>          }
>          writer.write("*");
>          if(msgs) {
>             writer.endElement("font");
>          }
>       }
>       writer.write(attrs.get("value").toString());
>    }
>
>    private boolean hasMessages(FacesContext context, UIComponent 
> component) {
>       Iterator it = context.getClientIdsWithMessages();
>       boolean found = false;
>
>       while(it.hasNext()) {
>          String id = (String)it.next();
>          if(component.getClientId(context).equals(id))
>             found = true;
>       }
>       return found;
>    }
> ...
>
> david
>
>>
>>>
>>> Thanks,
>>>
>>> Matt
>>>
>>>>
>>>>> Do I have to subclass the existing JSP Tag to do this?
>>>>
>>>>
>>>> You hardly ever want to subclass an existing component tag, because 
>>>> tags are really just thin veneers for component/renderer pairs. You 
>>>> could, however, implement your own Label renderer and plug it into 
>>>> h:outputLabel. But I would opt for one of the easier solutions 
>>>> above.
>>>>
>>>>> 2. Is it possible to auto-add a colon?  I'm able to do this pretty 
>>>>> easily with a custom taglib and Commons Validator, but it seems 
>>>>> difficult with MyFaces?  With Tapestry, I can subclass the 
>>>>> existing component and add my own suffix (including a space before 
>>>>> the colon for the French locale).
>>>>
>>>>
>>>> The same techniques for prepending an asterik will work for 
>>>> appending a colon. Again, you could implement your own Label 
>>>> renderer that does anything you want.
>>>>
>>>>
>>>> david
>>>>
>>>>>
>>>>> Thanks,
>>>>>
>>>>> Matt
>>>>>
>>>>
>>>
>>
>



Re: h:outputLabel - validation and colons

Posted by David Geary <sa...@earthlink.net>.
Le Dec 1, 2004, à 9:42 PM, David Geary a écrit :

[snip]

>> Hmmm, sounds like I have to have a getter method for each form field 
>> on my managed bean?  What a pain?
>>  Isn't there a way to look up if the field is required and just add a 
>> * - a solution that's generic for all outputLabel's?  I'm willing to 
>> hack source code or create components if I need to - I just need to 
>> know 2 things:
>>
>> 1.  Yes/No - if I have to hack the source to make the dynamic lookup 
>> possible?
>
> No hacking is required.
>
>> 2.  Where do I hack the source? I'm guessing there's some way to 
>> lookup the validation metadata for the inputs and use that data in 
>> the labels.
>
> You could implementing a replacement for the Label renderer:
>
> 1. In a renderer method such as encodeBegin(), get the value of the 
> renderer's component (encodeBegin is passed the component. Call the 
> component's getValue method). In this case, the component is the label 
> and the value is the id of the labeled component.
>
> 2. Get a reference to the labeled component. In a JSF component 
> hierarchy, any component can find any other component in the hierarchy 
> with the findComponent(String) method, where the String is the 
> component's id. So the label can find the labeled component.
>
> 3. Find out if the labeled component is required. Input components 
> implement the editableValueHolder interface, which defines an 
> isRequired method.
>
> 4. Render according to whether the labeled component is required.
>
>
> david

I went ahead and implemented this. After replacing the standard Label 
renderer, this...

<h:outputLabel for="name" value="#{msgs.namePrompt}"/>
<h:inputText id="name" value="#{registerForm.name}" />

...has a plain prompt, whereas the following has an asterik prepended 
to the prompt:

<h:outputLabel for="name" value="#{msgs.namePrompt}"/>
<h:inputText id="name" value="#{registerForm.name}" required="true"/>

Here's how it works. First, add this to your faces config file:

<faces-config>
    ...
    <render-kit>
       <description>Some replacements for the standard 
renderers</description>
       <renderer>
          <description>Replacement renderer for 
h:outputLabel</description>
          <component-family>javax.faces.Output</component-family>
          <renderer-type>javax.faces.Label</renderer-type>
          <renderer-class>renderers.LabelRenderer</renderer-class>
       </renderer>
    </render-kit>
</faces-config>

Because we didn't specify a renderkit name, JSF modifies the default 
renderkit by replacing the javax.faces.Label type renderer with our 
custom version.

Here's the renderer class:

package renderers;

import java.util.Map;
import javax.faces.component.UIComponent;
import javax.faces.component.UIInput;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import javax.faces.render.Renderer;

// Renderer for the Label components

public class LabelRenderer extends Renderer {
    public boolean getRendersChildren() {
       return false;
    }

    public void encodeBegin(FacesContext context, UIComponent component)
          throws java.io.IOException {
       ResponseWriter writer = context.getResponseWriter();
       writer.startElement("label", component);

       String styleClass = (String) 
component.getAttributes().get("styleClass");
       if (styleClass != null)
          writer.writeAttribute("class", styleClass, null);

       Map attrs = component.getAttributes();
       writer.writeAttribute("for", component.getClientId(context), 
null);

       UIInput input = 
(UIInput)component.findComponent((String)attrs.get("for"));
       if(input.isRequired())
          writer.write("*");

       writer.write(attrs.get("value").toString());
    }

    public void encodeEnd(FacesContext context, UIComponent component)
          throws java.io.IOException {
       ResponseWriter writer = context.getResponseWriter();
       writer.endElement("label");
    }
}

What's cool about this is that all h:outputLabel tags will be fitted 
with our custom renderer, so by modifying the config file and 
implementing the renderer, we are changing the behavior of existing JSP 
pages without modifying the pages themselves. All labels that decorate 
required fields will be prepended with asteriks.

Notice that my simple renderer is not industrial strength. It does not 
account for all the h:outputLabel attributes, nor does it allow a 
nested component. But it's not too bad for 20 minutes of work.

btw, it's easy to add an enhancement so that the asterik is red if the 
corresponding field failed validation. Here's the modified encodeBegin 
method of the renderer:

...
public void encodeBegin(FacesContext context, UIComponent component)
          throws java.io.IOException {
       ResponseWriter writer = context.getResponseWriter();
       writer.startElement("label", component);

       String styleClass = (String) 
component.getAttributes().get("styleClass");
       if (styleClass != null)
          writer.writeAttribute("class", styleClass, null);

       Map attrs = component.getAttributes();
       writer.writeAttribute("for", component.getClientId(context), 
null);

       UIInput input = 
(UIInput)component.findComponent((String)attrs.get("for"));
       if(input.isRequired()) {
          boolean msgs = hasMessages(context, input);
          if(msgs) {
             writer.startElement("font", null);
             writer.writeAttribute("color", "red", null);
          }
          writer.write("*");
          if(msgs) {
             writer.endElement("font");
          }
       }
       writer.write(attrs.get("value").toString());
    }

    private boolean hasMessages(FacesContext context, UIComponent 
component) {
       Iterator it = context.getClientIdsWithMessages();
       boolean found = false;

       while(it.hasNext()) {
          String id = (String)it.next();
          if(component.getClientId(context).equals(id))
             found = true;
       }
       return found;
    }
...

david
>
>>
>> Thanks,
>>
>> Matt
>>
>>>
>>>> Do I have to subclass the existing JSP Tag to do this?
>>>
>>> You hardly ever want to subclass an existing component tag, because 
>>> tags are really just thin veneers for component/renderer pairs. You 
>>> could, however, implement your own Label renderer and plug it into 
>>> h:outputLabel. But I would opt for one of the easier solutions 
>>> above.
>>>
>>>> 2. Is it possible to auto-add a colon?  I'm able to do this pretty 
>>>> easily with a custom taglib and Commons Validator, but it seems 
>>>> difficult with MyFaces?  With Tapestry, I can subclass the existing 
>>>> component and add my own suffix (including a space before the colon 
>>>> for the French locale).
>>>
>>> The same techniques for prepending an asterik will work for 
>>> appending a colon. Again, you could implement your own Label 
>>> renderer that does anything you want.
>>>
>>>
>>> david
>>>>
>>>> Thanks,
>>>>
>>>> Matt
>>>>
>>>
>>
>


Re: h:outputLabel - validation and colons

Posted by Craig McClanahan <cr...@gmail.com>.
In addition to what has been suggested earlier on this thread, there's
one additional thing you might want to do if you go the "customized
renderer" route for any of your changes -- tell the JSF runtime to use
*your* renderer instead of the standard one for the standard JSP tag. 
(I haven't tried this with MyFaces yet, but it works with the RI and
is designed in to the JSF APIs).

At runtime, JSF component tags look up the appropriate renderer in the
Application object, based on a combination of the values returned by
getComponentFamily() and getRendererType() on the component instance. 
So, in your own faces-config.xml, you can replace the registration for
the standard renderer for, say, the <h:outputLabel> tag, with an entry
like this:

    <renderer>
        ...
        <component-family>javax.faces.Output</component-family>
        <renderer-type>javax.faces.Label</renderer-type>
        <renderer-class>com.mycompany.mypackage.MyOutputLabelRenderer</renderer-class>
        ...
    </renderer>

The canonical identifiers you need are all defined in the JSF spec --
for component families, see the relevant component descriptions in
Chapter 4.  For standard renderer types, see Section 8.6.

Craig McClanahan


On Wed, 1 Dec 2004 21:42:27 -0700, David Geary <sa...@earthlink.net> wrote:
> Le Dec 1, 2004, à 9:18 PM, Matt Raible a écrit :
> 
> 
> 
> > On Dec 1, 2004, at 8:40 PM, David Geary wrote:
> >
> >> Le Dec 1, 2004, à 7:33 PM, Matt Raible a écrit :
> >>
> >>> Hello all,
> >>>
> >>> I've been doing a bit of MyFaces development this week and enjoying
> >>> it for the most part.
> >>
> >> Glad to hear it Matt! 8-)
> >>
> >>>  I have a couple questions about <h:outputLabel>:
> >>>
> >>> 1. Is there anyway to modify h:outputLabel to add an asterisk for
> >>> required fields?
> >>
> >> You can do that without modifying h:outputLabel, for example:
> >>
> >>    <h:loadBundle basename="messages" var="msgs"/>
> >>    ...
> >>    <h:outputLabel for="name" value="#{msgs.requiredNamePrompt}"/>
> >>
> >> In your resource bundle:
> >>
> >>    requiredNamePrompt=*Name
> >>
> >> Of course with that solution you're assuming the required state of
> >> the field in the view. That's probably better left to business logic,
> >> so you could do this instead:
> >>
> >>    <h:outputLabel for="name" value="#{backingBean.namePrompt}"/>
> >>
> >> And BackingBean.getNamePrompt() would return the proper localized
> >> string, with an asterik if the property is required, and without an
> >> asterik otherwise.
> >>
> >> Or, you could do this:
> >>
> >> <h:panelGroup>
> >>      <h:outputText value="*" rendered="#{backingBean.nameRequired}"/>
> >>      <h:outputLabel value="#{msgs.namePrompt}"/>
> >> </h:panelGroup>
> >>
> >> And have backingBean implement a boolean method named isNameRequired
> >> that returns the required status of the property in question. The
> >> h:outputText will only render if its rendered attribute is true.
> >
> > Hmmm, sounds like I have to have a getter method for each form field
> > on my managed bean?  What a pain?
> >  Isn't there a way to look up if the field is required and just add a
> > * - a solution that's generic for all outputLabel's?  I'm willing to
> > hack source code or create components if I need to - I just need to
> > know 2 things:
> >
> > 1.  Yes/No - if I have to hack the source to make the dynamic lookup
> > possible?
> 
> No hacking is required.
> 
> > 2.  Where do I hack the source? I'm guessing there's some way to
> > lookup the validation metadata for the inputs and use that data in the
> > labels.
> 
> You could implementing a replacement for the Label renderer:
> 
> 1. In a renderer method such as encodeBegin(), get the value of the
> renderer's component (encodeBegin is passed the component. Call the
> component's getValue method). In this case, the component is the label
> and the value is the id of the labeled component.
> 
> 2. Get a reference to the labeled component. In a JSF component
> hierarchy, any component can find any other component in the hierarchy
> with the findComponent(String) method, where the String is the
> component's id. So the label can find the labeled component.
> 
> 3. Find out if the labeled component is required. Input components
> implement the editableValueHolder interface, which defines an
> isRequired method.
> 
> 4. Render according to whether the labeled component is required.
> 
> 
> david
> 
> 
> 
> >
> > Thanks,
> >
> > Matt
> >
> >>
> >>> Do I have to subclass the existing JSP Tag to do this?
> >>
> >> You hardly ever want to subclass an existing component tag, because
> >> tags are really just thin veneers for component/renderer pairs. You
> >> could, however, implement your own Label renderer and plug it into
> >> h:outputLabel. But I would opt for one of the easier solutions above.
> >>
> >>> 2. Is it possible to auto-add a colon?  I'm able to do this pretty
> >>> easily with a custom taglib and Commons Validator, but it seems
> >>> difficult with MyFaces?  With Tapestry, I can subclass the existing
> >>> component and add my own suffix (including a space before the colon
> >>> for the French locale).
> >>
> >> The same techniques for prepending an asterik will work for appending
> >> a colon. Again, you could implement your own Label renderer that does
> >> anything you want.
> >>
> >>
> >> david
> >>>
> >>> Thanks,
> >>>
> >>> Matt
> >>>
> >>
> >
> 
>

Re: h:outputLabel - validation and colons

Posted by David Geary <sa...@earthlink.net>.
Le Dec 1, 2004, à 9:18 PM, Matt Raible a écrit :

> On Dec 1, 2004, at 8:40 PM, David Geary wrote:
>
>> Le Dec 1, 2004, à 7:33 PM, Matt Raible a écrit :
>>
>>> Hello all,
>>>
>>> I've been doing a bit of MyFaces development this week and enjoying 
>>> it for the most part.
>>
>> Glad to hear it Matt! 8-)
>>
>>>  I have a couple questions about <h:outputLabel>:
>>>
>>> 1. Is there anyway to modify h:outputLabel to add an asterisk for 
>>> required fields?
>>
>> You can do that without modifying h:outputLabel, for example:
>>
>>    <h:loadBundle basename="messages" var="msgs"/>
>>    ...
>>    <h:outputLabel for="name" value="#{msgs.requiredNamePrompt}"/>
>>
>> In your resource bundle:
>>
>>    requiredNamePrompt=*Name
>>
>> Of course with that solution you're assuming the required state of 
>> the field in the view. That's probably better left to business logic, 
>> so you could do this instead:
>>
>>    <h:outputLabel for="name" value="#{backingBean.namePrompt}"/>
>>
>> And BackingBean.getNamePrompt() would return the proper localized 
>> string, with an asterik if the property is required, and without an 
>> asterik otherwise.
>>
>> Or, you could do this:
>>
>> <h:panelGroup>
>> 	<h:outputText value="*" rendered="#{backingBean.nameRequired}"/>
>> 	<h:outputLabel value="#{msgs.namePrompt}"/>
>> </h:panelGroup>
>>
>> And have backingBean implement a boolean method named isNameRequired 
>> that returns the required status of the property in question. The 
>> h:outputText will only render if its rendered attribute is true.
>
> Hmmm, sounds like I have to have a getter method for each form field 
> on my managed bean?  What a pain?
>  Isn't there a way to look up if the field is required and just add a 
> * - a solution that's generic for all outputLabel's?  I'm willing to 
> hack source code or create components if I need to - I just need to 
> know 2 things:
>
> 1.  Yes/No - if I have to hack the source to make the dynamic lookup 
> possible?

No hacking is required.

> 2.  Where do I hack the source? I'm guessing there's some way to 
> lookup the validation metadata for the inputs and use that data in the 
> labels.

You could implementing a replacement for the Label renderer:

1. In a renderer method such as encodeBegin(), get the value of the 
renderer's component (encodeBegin is passed the component. Call the 
component's getValue method). In this case, the component is the label 
and the value is the id of the labeled component.

2. Get a reference to the labeled component. In a JSF component 
hierarchy, any component can find any other component in the hierarchy 
with the findComponent(String) method, where the String is the 
component's id. So the label can find the labeled component.

3. Find out if the labeled component is required. Input components 
implement the editableValueHolder interface, which defines an 
isRequired method.

4. Render according to whether the labeled component is required.


david

>
> Thanks,
>
> Matt
>
>>
>>> Do I have to subclass the existing JSP Tag to do this?
>>
>> You hardly ever want to subclass an existing component tag, because 
>> tags are really just thin veneers for component/renderer pairs. You 
>> could, however, implement your own Label renderer and plug it into 
>> h:outputLabel. But I would opt for one of the easier solutions above.
>>
>>> 2. Is it possible to auto-add a colon?  I'm able to do this pretty 
>>> easily with a custom taglib and Commons Validator, but it seems 
>>> difficult with MyFaces?  With Tapestry, I can subclass the existing 
>>> component and add my own suffix (including a space before the colon 
>>> for the French locale).
>>
>> The same techniques for prepending an asterik will work for appending 
>> a colon. Again, you could implement your own Label renderer that does 
>> anything you want.
>>
>>
>> david
>>>
>>> Thanks,
>>>
>>> Matt
>>>
>>
>


Re: h:outputLabel - validation and colons

Posted by Matt Raible <li...@raibledesigns.com>.
On Dec 1, 2004, at 8:40 PM, David Geary wrote:

> Le Dec 1, 2004, à 7:33 PM, Matt Raible a écrit :
>
>> Hello all,
>>
>> I've been doing a bit of MyFaces development this week and enjoying 
>> it for the most part.
>
> Glad to hear it Matt! 8-)
>
>>  I have a couple questions about <h:outputLabel>:
>>
>> 1. Is there anyway to modify h:outputLabel to add an asterisk for 
>> required fields?
>
> You can do that without modifying h:outputLabel, for example:
>
>    <h:loadBundle basename="messages" var="msgs"/>
>    ...
>    <h:outputLabel for="name" value="#{msgs.requiredNamePrompt}"/>
>
> In your resource bundle:
>
>    requiredNamePrompt=*Name
>
> Of course with that solution you're assuming the required state of the 
> field in the view. That's probably better left to business logic, so 
> you could do this instead:
>
>    <h:outputLabel for="name" value="#{backingBean.namePrompt}"/>
>
> And BackingBean.getNamePrompt() would return the proper localized 
> string, with an asterik if the property is required, and without an 
> asterik otherwise.
>
> Or, you could do this:
>
> <h:panelGroup>
> 	<h:outputText value="*" rendered="#{backingBean.nameRequired}"/>
> 	<h:outputLabel value="#{msgs.namePrompt}"/>
> </h:panelGroup>
>
> And have backingBean implement a boolean method named isNameRequired 
> that returns the required status of the property in question. The 
> h:outputText will only render if its rendered attribute is true.

Hmmm, sounds like I have to have a getter method for each form field on 
my managed bean?  What a pain?  Isn't there a way to look up if the 
field is required and just add a * - a solution that's generic for all 
outputLabel's?  I'm willing to hack source code or create components if 
I need to - I just need to know 2 things:

1.  Yes/No - if I have to hack the source to make the dynamic lookup 
possible?
2.  Where do I hack the source? I'm guessing there's some way to lookup 
the validation metadata for the inputs and use that data in the labels.

Thanks,

Matt

>
>> Do I have to subclass the existing JSP Tag to do this?
>
> You hardly ever want to subclass an existing component tag, because 
> tags are really just thin veneers for component/renderer pairs. You 
> could, however, implement your own Label renderer and plug it into 
> h:outputLabel. But I would opt for one of the easier solutions above.
>
>> 2. Is it possible to auto-add a colon?  I'm able to do this pretty 
>> easily with a custom taglib and Commons Validator, but it seems 
>> difficult with MyFaces?  With Tapestry, I can subclass the existing 
>> component and add my own suffix (including a space before the colon 
>> for the French locale).
>
> The same techniques for prepending an asterik will work for appending 
> a colon. Again, you could implement your own Label renderer that does 
> anything you want.
>
>
> david
>>
>> Thanks,
>>
>> Matt
>>
>


Re: h:outputLabel - validation and colons

Posted by David Geary <sa...@earthlink.net>.
Le Dec 1, 2004, à 7:33 PM, Matt Raible a écrit :

> Hello all,
>
> I've been doing a bit of MyFaces development this week and enjoying it 
> for the most part.

Glad to hear it Matt! 8-)

>  I have a couple questions about <h:outputLabel>:
>
> 1. Is there anyway to modify h:outputLabel to add an asterisk for 
> required fields?

You can do that without modifying h:outputLabel, for example:

    <h:loadBundle basename="messages" var="msgs"/>
    ...
    <h:outputLabel for="name" value="#{msgs.requiredNamePrompt}"/>

In your resource bundle:

    requiredNamePrompt=*Name

Of course with that solution you're assuming the required state of the 
field in the view. That's probably better left to business logic, so 
you could do this instead:

    <h:outputLabel for="name" value="#{backingBean.namePrompt}"/>

And BackingBean.getNamePrompt() would return the proper localized 
string, with an asterik if the property is required, and without an 
asterik otherwise.

Or, you could do this:

<h:panelGroup>
	<h:outputText value="*" rendered="#{backingBean.nameRequired}"/>
	<h:outputLabel value="#{msgs.namePrompt}"/>
</h:panelGroup>

And have backingBean implement a boolean method named isNameRequired 
that returns the required status of the property in question. The 
h:outputText will only render if its rendered attribute is true.

> Do I have to subclass the existing JSP Tag to do this?

You hardly ever want to subclass an existing component tag, because 
tags are really just thin veneers for component/renderer pairs. You 
could, however, implement your own Label renderer and plug it into 
h:outputLabel. But I would opt for one of the easier solutions above.

> 2. Is it possible to auto-add a colon?  I'm able to do this pretty 
> easily with a custom taglib and Commons Validator, but it seems 
> difficult with MyFaces?  With Tapestry, I can subclass the existing 
> component and add my own suffix (including a space before the colon 
> for the French locale).

The same techniques for prepending an asterik will work for appending a 
colon. Again, you could implement your own Label renderer that does 
anything you want.


david
>
> Thanks,
>
> Matt
>