0

I have a custom component location. I want that, when a change is done, the model is update so another component (an autocomplete) is to show only results related to the location value. Also, that component is rerendered to reset it.

I have a page with the following code (simplified):

<h:form id="ticketForm">
  ...
  <loc:location id="locationId"                         <-- CUSTOM COMPONENT
    hiddenFieldValue="#{ticketCtrl.ticket.location}"
    visibleFieldValue="#{ticketCtrl.ticket.locationDescription}"
    rendered="#{ticketCtrl.ticketModifiable}">

    <f:ajax event="changeLocation" render=":ticketForm:gfhId"       <-- AJAX CALL.
      execute=":ticketForm:locationId" listener="#{ticketCtrl.locationListener}"/>
  </loc:location>
  ...
</h:form>

When the value in the component is changed, the model is updated and :ticketForm:gfhId is rendered as needed, but the listener(which performs additional resets) is not executed.

Attaching the ajax to a simpler control results in the listener being executed; v.g.

<h:inputText id="contactId"
  value="#{ticketCtrl.ticket.contactPerson}"
  disabled="#{not ticketCtrl.ticketModifiable}">
  <f:ajax event="change" render=":ticketForm:gfhId"
    execute=":ticketForm:locationId" listener="#{ticketCtrl.locationListener}"/>
</h:inputText>

works perfectly.

I do not know if it may be related as how the changeLocation event is fired; inside my component I define it as

<composite:interface>
   ...
   <composite:clientBehavior name="changeLocation" event="change" targets="visibleId"/>
</composite:interface>

with visibleId being a readonly text; when it is changed by javascript I fire the change event on it with JS.

function launchEvent(fieldName) {
  if ("fireEvent" in fieldName) {
    fieldName.fireEvent("onchange");
  } else {
    var evt = document.createEvent("HTMLEvents");
    evt.initEvent("change", false, true);
    fieldName.dispatchEvent(evt);
  }
}

The info I find in other questions is about making ajax an inner part of the composite component, here I want ajax detached because I probably won't need it in other uses of the component.

I am using JBoss 6.1 wih Mojarra 2.1.9 and Richfaces 4.

Thanks in advance.

UPDATE:

Even after finding jarek.jpa's answer right, if someone wants to check the code it is here:

The composite component http://pastebin.com/9wqMVfR5

The main form http://pastebin.com/i39ys2D9

SJuan76
  • 24,532
  • 6
  • 47
  • 87
  • Please provide an SSCCE. Do as if you're the answerer and you try to reproduce this problem so that you could just run the debugger to spot the cause. Create a new blank JSF project. Copy the code provided in this question without knowing anything about your real business code. Is the code provided so far sufficient to reproduce the problem? It wasn't for me. I couldn't reproduce nor understand your problem based on the code provided so far. The listener get invoked just fine. The root cause is not visible in the code provided so far. – BalusC Sep 19 '12 at 23:37
  • @BalusC Thanks for your interest; jarek.jpa's answer works for me. Anyway, for if it is of interest, I updated my question to pastebins to the whole XHTML code. – SJuan76 Sep 20 '12 at 08:53

1 Answers1

1

This may have to do with the "readonly" attribute set to true. Though you manage to send the change-event by hand (JS), the server-side processing of the listener may be dropped due to the readonly state. See e.g. jsf (richfaces) readonly input text validation.

Community
  • 1
  • 1
jarek.jpa
  • 565
  • 1
  • 5
  • 18
  • Right. Made a hidden field that was inside the component visible, changes to it (or programmatically launching the event) caused the listener to be executed. Alternatively, attached the `f:ajax` to other componenet in the main form when it was clicked, when it was made `readonly="true"` the listener no longer was executed. I wasn't expecting that, I thought it was because it was a composite or because I was launching the event from JS code. Thanks! – SJuan76 Sep 20 '12 at 08:36
  • Still cannot award the bounty, just wait a few hours. – SJuan76 Sep 20 '12 at 08:37
  • One additional question, using this trick works but forces me to provide a dummy setter for the readonly field. Since I am opposed to dummy methods, I tried setting `readonly` to `true` in other states(i.e. `readonly="#{facesContext.currentPhaseId.ordinal eq 2 or facesContext.currentPhaseId.ordinal eq 6}") but there are no combinations that spare me providing such a method. Any idea? – SJuan76 Sep 20 '12 at 12:10
  • Glad to have been of help :) As to the dummy setter and changing a read-only field - why not to stick with the natural semantics where read-only means "cannot be changed" and instead pass the change in parallel, through some other (hidden) field? Then either process the change server side, and send it back to client, or -if the processing logic should stay on the client- just send the processed new value to the server and rewrite it appropriately to the read-only field. That way you stay clear with the intentions and don't have to resort to the tricks with conditions based on current phase. – jarek.jpa Sep 20 '12 at 13:41