Validator with attributes for composite component
Asked Answered
N

1

1

I want to create validator for composite component where I want to pass few attributes. This is how code looks like (it's not original code but is implemented in the same way):

Composite component (compositeComponent.xhtml)

<h:body>
    <composite:interface componentType="compositeComponent">
        <composite:attribute name="name" required="true" />
        <composite:attribute name="value" required="true" />
        <composite:attribute name="values" required="true" />
        <composite:editableValueHolder name="validator" targets="#{cc.attrs.id}"/>
    </composite:interface>
    <composite:implementation>
        <h:selectOneMenu value="#{cc.attrs.value}" id="#{cc.attrs.id}">
            <f:selectItems value="#{cc.attrs.values}" var="item" itemValue="#{item.value}" itemLabel="#{item.label}" />
            <composite:insertChildren/>
        </h:selectOneMenu>
    </composite:implementation>
</h:body>

As you can see I want to pass validator to h:selectOneMenu. Composite component can be (to be more precisely 'should be' because it currently doesn't work) used in this way:

<ns:compositeComponent name="myComp" value="#{controller.value}" values="#{controller.values}">
    <f:validator validatorId="myValidator" for="validator">
        <f:attribute name="param1" value="param1Value"/>
        <f:attribute name="param1" value="param1Value"/>
    </validator>
</ns:compositeComponent>

I tested this code and validator is called if i don't pass attributes into it.

<ns:compositeComponent name="myComp" value="#{controller.value}" values="#{controller.values}">
    <f:validator validatorId="myValidator" for="validator"/>
</ns:compositeComponent>

I found that attributes can be passed in this way:

<ns:compositeComponent name="myComp" value="#{controller.value}" values="#{controller.values}">
    <f:validator validatorId="myValidator" for="validator"/>
    <f:attribute name="param1" value="param1Value"/>
    <f:attribute name="param1" value="param1Value"/>
</ns:compositeComponent>

but (as far as I know) only validator will be injected to custom component (thats why for="validator" is set on validator) so I won't be able to get these attributes. How can I pass attributes to this validator?

BTW. If it's possible I will want to pass parameters as nested elements because it looks more clear. This one:

<f:selectOneMenu>
    <f:validator validatorId="myValidator">
        <f:attribute name="param1" value="value1"/>
    </f:validator>
</f:selectOneMenu>

instead of this one:

<f:selectOneMenu>
    <f:validator validatorId="myValidator"/>
    <f:attribute name="param1" value="value1"/>
</f:selectOneMenu>
Neace answered 21/2, 2014 at 14:33 Comment(0)
N
4

I found that <f:validator/> cant have nested elements so this one won't work:

<f:validator validatorId="myValidator">
    <f:attribute name="param1" value="value1"/>
</f:validator>

To solve my problem I've created custom validator. To do it I had to:

Create taglib.xml file in WEB-INF dir.

<?xml version="1.0"?>
<!DOCTYPE facelet-taglib PUBLIC
  "-//Sun Microsystems, Inc.//DTD Facelet Taglib 1.0//EN"
  "http://java.sun.com/dtd/facelet-taglib_1_0.dtd">
<facelet-taglib>
    <namespace>http://customtag.com/tags</namespace>
    <tag>
        <tag-name>uniqueValidator</tag-name>
        <validator>
            <validator-id>simpleValidator</validator-id>
        </validator>
        <!-- To show hints on this component add this but it's not required -->
        <attribute>
            <description>List of elements to check. Validation succeeds if each item is unique (equals() method is used to compare items).</description>
            <name>items</name>
            <required>true</required>
        </attribute>
    </tag>
</facelet-taglib>

Register taglib.xml in web.xml

<context-param>
    <param-name>javax.faces.FACELETS_LIBRARIES</param-name>
    <param-value>/WEB-INF/taglib.xml</param-value>
</context-param>

Write validator code

package validator;

import java.util.List;

import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.validator.FacesValidator;
import javax.faces.validator.Validator;
import javax.faces.validator.ValidatorException;

@FacesValidator("simpleValidator")
public class SimpleValidator implements Validator {

    private List<Object> items;

    @Override
    public void validate(final FacesContext arg0, final UIComponent arg1, final Object arg2) throws ValidatorException {
        // use items list
    }

    public void setItems(final List<Object> items) {
        this.items = items;
    }

}

This is how it can be used in view / composite component:

<mycomp:custom name="test11">
    <myval:uniqueValidator items="#{model.values}" for="validator"/>
</mycomp:custom>

Of course to use validator in custom component I had to define editableValueHolder and inject/paste it using insertChildren (see my question).

Neace answered 23/2, 2014 at 9:8 Comment(2)
Eclipse gives an error in the taglib.xml: The content of element type "tag" must match "(tag-name,(handler-class|component|converter|validator|source))".Ilk
Your taglib.xml file doesn't validate. You should use: <facelet-taglib xmlns="java.sun.com/xml/ns/javaee" xmlns:xsi="w3.org/2001/XMLSchema-instance" xsi:schemaLocation="java.sun.com/xml/ns/javaee java.sun.com/xml/ns/javaee/web-facelettaglibrary_2_0.xsd" version="2.0"> And remove the DOCTYPELinville

© 2022 - 2024 — McMap. All rights reserved.