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 <[EMAIL PROTECTED]> 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
> >>>>>
> >>>>
> >>>
> >>
> >
> 
>

Reply via email to