javajsfbindingrichfaces

JSF throws argument type mismatch when binding


I'm trying to do the following: When the user enters a value in the rich:calendar component, then the h:inputText should have its required attributed set to true. I'm following the instructions in this post: Reference JSF control's attributes via JavaScript

Sorry for creating another post, but I couldn't figure out how to post the code into the comments area and make it readable. The page throws this error:

javax.el.ELException: /pages/overtime/overtime-n.xhtml @121,65 binding="#{oc.overtimeDate}": java.lang.IllegalArgumentException: argument type mismatch

The problem is that the binding is inside a c:forEach loop, and I'm trying to use the loop variable to bind to. The overtime.overtimeItems is defined as an ArrayList<OvertimeComponent> with each OvertimeComponent object having various properties (overtimeDate, overtimeDateId, id, overtimeHours, etc.).

<c:forEach items="#{overtime.overtimeItems}" var="oc">
  <rich:calendar value="#{oc.overtimeDate}" 
    requiredMessage="Date 1 is required."
    id="#{oc.overtimeDateId}" 
    binding="#{oc.overtimeDate}" 
    required="#{oc.id == 1 ? true : false}">
  </rich:calendar>
  <h:inputText value="#{oc.overtimeHours}" 
    id="#{oc.overtimeHoursId}"
    requiredMessage="Hours is required." 
    required="#{not empty oc.overtimeDate.value}" >
  </h:inputText>
  .....
</c:forEach>

How do I make the h:inputText required if the rich:calendar object has a value? There's a way to do this using the binding property of the calendar, but I'm not sure how to do it inside a c:forEach. I can't use AJAX for this project. Thanks.


Solution

  • The binding attribute should point to an UIComponent, not to a value object like Date. The answer in your previous question would have worked if you wasn't using c:forEach.

    <rich:calendar value="#{oc.overtimeDate}" 
        requiredMessage="Date 1 is required."
        id="#{oc.overtimeDateId}" 
        binding="#{calendarComponent}" 
        required="#{oc.id == 1 ? true : false}">
    </rich:calendar>
    <h:inputText value="#{oc.overtimeHours}" 
        id="#{oc.overtimeHoursId}"
        requiredMessage="Hours is required." 
        required="#{not empty calendarComponent.value}" >
    </h:inputText>
    

    The above example binds the component to the "page scope", not to a particular bean since you're usually not interested in the component from inside the bean. You can name #{calendarComponent} whatever you want. You can access it anywhere in the same page by the same name.

    However, in your particular case you're using c:forEach and not ui:repeat, so components are actually repeated in the component tree (the ui:repeat only repeats in the HTML renderer). This means that you cannot use the suggested approach. All components would then share the same binding which is wrong. Best would be to add an UIComponent (more precise, UIInput) property to the object behind oc and bind to it instead, so that every component has its own unique binding. E.g.

    public class OvertimeComponent {
        private UIInput calendarComponent;
        // ...
    

    with

    <rich:calendar value="#{oc.overtimeDate}" 
        requiredMessage="Date 1 is required."
        id="#{oc.overtimeDateId}" 
        binding="#{oc.calendarComponent}" 
        required="#{oc.id == 1}">
    </rich:calendar>
    <h:inputText value="#{oc.overtimeHours}" 
        id="#{oc.overtimeHoursId}"
        requiredMessage="Hours is required." 
        required="#{not empty oc.calendarComponent.value}" >
    </h:inputText>
    

    (note that I simplified the EL of the required attribute of rich:calendar since it already returns a boolean anyway)