Can't define a event and bind an <a4j:support/> on this event at the same time - jsf

Let's consider this simple code:
<h:form id="myForm">
<h:inputText id="myInput">
<a4j:support event="onchange" actionListener="#{myBean.doSomething}"/>
</h:inputText>
</h:form>
this will generate the following HTML code:
<input id="myForm:myInput" type="text" name="myForm:myInput" onchange="A4J.AJAX.Submit(...)" />
Now, I just add something in the onchange event of my <h:inputText>:
<h:form id="myForm">
<h:inputText id="myInput" onchange="alert('foobar');">
<a4j:support event="onchange" actionListener="#{myBean.doSomething}"/>
</h:inputText>
</h:form>
This will generate the following HTML code:
<input id="myForm:myInput" type="text" name="myForm:myInput" onchange="alert('foobar');" />
As you can see, the Ajax code is not added anymore. This is a really strange behavior as far as I am concerned. Why the <a4j:support> does not attach the Ajax call if the event is already defined in the input field?
So my question is how to make the <a4j:support> working on an event that is already defined in the input? Of course, the solution must run both the Javascript code defined in onchange and the Ajax call.
In others words, I would like to have the following HTML:
<input id="myForm:myInput" type="text" name="myForm:myInput" onchange="alert('foobar'); A4J.AJAX.Submit(...)" />
I am using Richfaces 3.3.2 and JSF 1.2
EDIT
Of course, I can move the onchange Javascript code in the onsubmit attribute of the <a4j:support>, doing something like that:
<h:inputText id="myInput">
<a4j:support onsubmit="alert('foobar');" event="onchange" actionListener="#{myBean.doSomething}"/>
</h:inputText>
But is it the only way??

If this behaviour is not explicitly documented, I would consider this as a bug in Ajax4jsf. Report it to Ajax4jsf/RichFaces guys over there at JBoss.org. I've seen problems like that before with <a4j:commandButton onclick="someFunction()">

I already had this problem before, and I found that RichFaces 3.3.x will execute only the code for the onchange event defined with a4j:support and will ignore the onchange code defined with the JSF component.
In my case the workaround was simple, for my case it was valid to use other event instead of "onchange" (not sure if it was onclick or onselect), so I attached my code to this other event and my code worked, but I'm not sure if this could work for you. If you really need the onchange event for both elements, you'll have to do just as BalusC said and report it to the RichFaces folks.

More about the context
In fact, I can't really modify the event value of the <a4j:support>, like suggesteed by Abel Morelos, because what I am trying to do is to add a custom component that execute some client-side validation. This validation calls a Javascript function, so my custom component modifies the onchange value of his parent.
My JSF code will looks like:
<h:inputText id="myInput">
<my:validation .../>
<a4j:support event="onchange" actionListener="#{myBean.doSomething}"/>
</h:inputText>
This code is quite equivalent to the following code, except that the onchange of the <h:inputText> is added automatically by my component:
<h:inputText id="myInput" onchange="if (!checkSomeValidation()) { return false; }">
<a4j:support event="onchange" actionListener="#{myBean.doSomething}"/>
</h:inputText>
So as you can understand, my custom component directly modifies the onchange event of the <h:inputText>, and due to the problem with <a4j:support>, the Ajax call is not binded to the input component at the end.
The solution
When linked to a JSF component, the <a4j:support> will "transform" itself to a facet, whose name is org.ajax4jsf.ajax.SUPPORTxxx, where xxx is the event name. So in my case, the <h:inputText> will have a facet named org.ajax4jsf.ajax.SUPPORTonchange.
So what I do in my Java code of my custom component, is to check if the parent (the <h:inputText> here), has such a facet.
If no, it means that the parent has no <a4j:support event="onchange"/> linked to it. So in this case, I modify the onchange attribute of my <h:inputText/>
If yes, it means that there is a <a4j:support event="onchange"/> linked to the parent. So I modify the facet itself using the following code:
HtmlAjaxSupport facet = (HtmlAjaxSupport) getParent().getFacet("org.ajax4jsf.ajax.SUPPORTonchange");
if (facet != null) {
facet.setOnsubmit("my Javascript code goes here");
} else {
getParent().setOnchange("my Javascript goes here");
}

Related

How to call listener or backing bean method after completing a javascript call in jsf?

According to my scenario, Need to invoke the javascript first. After the javascript call two hidden values will be updated. With the updated hidden values , have to call Bean method. In this scenario, I am getting called javascript and bean method at the same time. So In my bean method, I am not getting the updated values in the hidden fields.
Little bit detail explanation
Textbox(address) is used to type address. And having two hidden elements which will used to store street name and city name based on the address field.
By the Javascript call, Collecting two values (Street name and City name) from the google maps API (codeAddress()). Based on the entered address in the textbox updating the two hidden fields(street and city). Bean method has to handle With the updated hidden values.
But From my code, Backing bean and the java script is called simultaneously. So I am not getting the Updated value in the Backing Bean.
My code is following :
JSF CODE
<h:form prependId="false">
<div id="panel-one">
<h:outputLabel value="ADDRESS"/>
<h:inputText type="text" id="address" size="40" value="#{Bean.address}"/>
<h:inputHidden id="street" value="#{Bean.streetName}" />
<h:inputHidden id="city" value="#{Bean.city}" />
<h:commandButton type="submit" value="Verify Address"
onclick="checkAddress()">
<f:ajax execute="#form" render="#none" listener="#{Bean.checkAddress()}"/>
</h:commandButton>
</div>
</h:form>
Javascript
checkAddress() {
document.getElementById("street").value = //Setting value from other javascript API;
document.getElementById("city").value = //Setting value from other javascript API;
}
In the above javascript collecting values and setting it with two textbox. With the updated values again calling the checkAddress() method in backing bean. FYI : *checkAddress()* is a AJAX CALL. I am doing mistake in h:commandButton of JSF , but dont know how to fix it. Any help is much appreciated.
There're several things odd with your provided code:
I don't see a need for prependId
Defining onclick on a commandButton is a bad idea[tm]
You're setting yourself and/or the person inheriting that code up for a headache by having a JS function and a bean method both called checkAddress
You don't seem to do anything based upon the fired action? (having render="#none")
That said, a kind of hack that should do what you need is hiding the actual button and clicking it programmatically:
<h:form id="addrF">
<h:outputLabel value="ADDRESS"/>
<h:inputText type="text" id="address" size="40" value="#{bean.address}"/>
<button class="clickMe">Verify Address</button>
<h:inputHidden id="street" value="#{bean.streetName}" />
<h:inputHidden id="city" value="#{bean.city}" />
<h:commandButton id="submitBtn" style="display:none;">
<f:ajax execute="#form" render="#none" listener="#{Bean.checkAddress()}"/>
</h:commandButton>
</h:form>
<h:outputScript>
$(".clickMe").click(function(ev) {
ev.preventDefault();
$.getJSON(
"https://maps.googleapis.com/maps/api/geocode/json",
{ address : $("#addrF\\:address").val() },
function(data) {
// set street, city
$('#addrF\\:submitBtn').click();
}
);
});
</h:outputScript>
You probably want additional value validation, etc. and your access to the maps API might be different (I haven't used it at all). The point is: you need to click() on the hidden commandButton only after your ajax call completed.
Please try using event="" in f:ajax and then use onevent to call javascript function.
Event value would be "click" and onevent value would be name of javascript function. like
You could try to set a Delay for the JavaScript setTimeout()
<h:commandButton type="submit" value="Verify Address"
onclick="setTimeout(function(){checkAddress()},1000);">
1000 miliseconds = 1 second, you just change that value for your convenience

Reset inputText after Button Click with JSF

Is it possible to reset the value of an inputText after clicking on the commandButton in JSF? The inputText UIElement provides the method ResetValue so I tried something like this:
<h:inputText id="measurementadd" binding="#{inputTextMeasurement}">
<f:validateRegex pattern="[a-zA-Z ]*"/>
<f:ajax event="keyup" render="measurementaddmessage submit" execute="#this"/>
<h:inputText>
<p:commandButton id="submit" action="#{Bean.addMeasurement(inputTextMeasurement.value)}"
value="submit" update="dataTable measurementadd measurementaddmessage"
disabled="#{empty inputTextMeasurement.value or facesContext.validationFailed }" >
<f:ajax event="mouseup" execute="#{inputTextMeasurement.resetValue()}" />
</p:commandButton>
<h:messages for="measurementadd" id="measurementaddmessage"/>
But after clicking the Button the inputTextMeasurement doesn't reset it's value.
Does someone know a good workaround for this?
I'm searching for a solution without JS and JAVA, so a realization in JSF would be very cool.
Your mistake is here in the execute attribute:
<f:ajax event="mouseup" execute="#{inputTextMeasurement.resetValue()}" />
The execute attribute should represent a space separated collection of client IDs to include in the process/decode of the ajax request. However, you specified a listener method there.
You need the listener attribute instead:
<f:ajax listener="#{inputTextMeasurement.resetValue()}" />
(and I omitted event as it defaults here to click which is already the right one)
Interesting detail is that the other <f:ajax> in the same piece of code used the exeucte attribute the right way.
Unrelated to the concrete problem, have you looked at <p:resetInput>? This saves an ajax listener method in the bean. Replace the whole <f:ajax> with
<p:resetInput target="measurementadd" />
Why dont we just use
<input type="Reset"/>
This one is works fine for me! ???
I have solved my problem as below
<p:commandButton id="submit" action="#{Bean.addMeasurement(inputTextMeasurement)}">
Sending back bean UIInput component. Get and Reset value in back bean.
public void addMeasurement(UIInput
String msr = (String) inputTextMeasurement.getValue()
inputTextMeasurement.resetValue();
}

How to access POST parameters when validation failed

I need to show the response page depending on some of the input fields. E.g. the tabid inputHidden below:
#{controllerBean.tabId}
...
<h:form id="edit">
<h:inputHidden value="#{controllerBean.tabId}" id="tabid" />
<h:inputText value="#{controllerBean.name}" id="name" />
</h:form>
But when some other input in the same form has validation error (e.g. the "name" inputText). The "controllerBean.tabId" value will not be assigned because JSF returns at validation stage.
I still need the tabId to show the page correctly and having 2 ideas in mind:
#{param['edit:tabid']}
or use binding:
#{tabId.value}
<h:inputHidden value="#{controllerBean.tabId}" id="tabid" binding="tabId" />
My question is, which of these 2 is the better or Best Practice? Or there are even better ways to do this?
update:
Note. In my specific case, the tabid is set by client javascript.
Server reply with a few items in the html.
Javascript put these items into different tabs on the page.
One of the tabs POST data to server with the current tabid in the form.
So my server need to know the tabid to show the response page with the correct tab selected.
You can add a lifecycle event listener to the component and pick the value from it. I'm going to recommend the preValidate listener:
<h:form id="edit">
<h:inputHidden value="#{controllerBean.tabId}" id="tabid">
<f:event type="preValidate" listener="#{controller.grabTabId}"/>
</h:inputHidden>
<h:inputText value="#{controllerBean.name}" id="name" />
</h:form>
This registers the listener to fire just before the validation phase of the request. You'll now have a listener defined in your backing bean to look like:
public void grabTabId(ComponentSystemEvent cse){
//obtain a reference to the component
HtmlInputHidden hiddenElement = (HtmlInputHidden)cse.getComponent();
//get the value from the component.
String hiddenValue = hiddenElement.getValue();
}
<h:form id="edit">
<h:inputHidden value="#{controllerBean.tabId}" id="tabid" />
<h:inputText value="#{controllerBean.name}" id="name" >
<p:ajax process="tabid" immediate="true" event="keyup" />
</h:inputText>
</h:form>
The above code will do is when the user put some value the value will be processed and will be set the managedBean. that what you want I think.
Another non-perfect way of accomplishing this is to move the validation logic to your action method. If validation fails, you just stop processing (and add an applicable FacesMessage). You just need to be aware that all model values will have been updated, and you can clear them if necessary.
Since updating model values on failed validation goes against the JSF lifecycle, I think any solution will be somewhat of a hack.

Javascript error in XHTML page in JSF 2

I have the following code in an xhtml page in JSF 2. But when the page loads I get an javascript error that
document.getElementById("country") is null or not an object.
Why is this happening?
<h:form>
<h:panelGrid columns="2">
Selected country locale :
<h:inputText id="country" value="#{country.localeCode}" size="20" />
Select a country {method binding}:
<h:selectOneMenu value="#{country.localeCode}" onchange="submit()"
valueChangeListener="#{country.countryLocaleCodeChanged}">
<f:selectItems value="#{country.countryInMap}" />
</h:selectOneMenu>
<script>
alert("hi");
document.getElementById("country").disabled=true;
</script>
</h:panelGrid>
</h:form>
It's not finding your component. Since your <h:inputText> is inside of an <h:form> the id will have the following pattern
formName:componentName. Since you did not specify an id for <h:form>, JSF will generate one for you. That's why you are seeing j_id1926454887_72d35e53:country where j_id1926454887_72d35e53 is the form id. If you want to deal with simpler id, then you should add an id value to your <h:form>. For example
<h:form id="form">
<h:inputText id="country" value="#{country.localeCode}" size="20" />
</h:form>
The id for <h:inputText> will now be form:country.
Even simpler, you could simply add prependId = "false" to your form
<h:form prependId="false">
and now your id for <h:inputText> will simply be country.
How can I get this id dynamically?
I'm going to modify your code slightly to achieve what you want (I'm thinking that you want to disable the input based on a specific event). Consider this simpler example
<h:form>
<h:inputText id="country" value="#{country.localeCode}" size="20" onclick="disableInputText(this.form)" />
</h:form>
Here I'm attaching a javascript function to an HTML DOM Event handler. In this case, I want the input to be disabled when I click on it (hence onclick). I'm also passing the form as a reference in the function. Then, define your Javascript like this.
<script>
function disableInputText(form) {
form[form.id + ":country"].disabled = true;
}
</script>
We simply grab the input in the javascript with the corresponding id via the object form and set its disabled attribute to true. (You can sort of view the form object as Map).
Also check the link below for more attributes of <h:inputText> and the different handlers you can use (the ones with on as prefix).
inputText Tag Attribute.
Also, check out the answer with the most votes to get a bigger picture on how ids are generated and other ways on how they can be determined.
How can I know the id of a JSF component so I can use in Javascript
It's seems to be a naming issue. the id of the field is not rendered as country.
i found a question that seems relevant. Composite components & ID

Show Richfaces Component on event selection

I would like to know how could I retrieve my jsf component value, when an event is executed. For example consider this component:
<rich:select id="selectEmpresa"
value="#{macroprocesoController.empresaSeleccionada}"
converter="genericConverter" enableManualInput="true" onchange="if(!#{rich:component('selectEmpresa')}.getValue()) return false;">
<f:selectItems value="#{selectItemsController.empresaItems}" />
<a4j:ajax execute="#this" render="macroProcesosTable" event="selectitem" listener="#{macroprocesoController.empresaSelectedListener}"></a4j:ajax>
<a4j:ajax execute="#this" render="macroProcesosTable" event="change" listener="#{macroprocesoController.empresaSelectedListener}"></a4j:ajax>
</rich:select>
What I want is to conditionally execute the a4j:ajax for the change event, so that when the component executes the selectitem event, and thus setting a value, the change event will be bypassed. However this is not working, any suggestions or a way to do what I need?
onchange="if(!#{rich:component('selectEmpresa')}.getValue()) return false;"
This expression is evaluated when the view is rendered, not when the DOM event executes (check the generated HTML source to see it yourself). You'd need to use JavaScript instead to get the current value. The following should do:
onchange="if (!this.value) return false;"
or just
onchange="return !!value;"

Resources