How to call listener or backing bean method after completing a javascript call in jsf? - 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

Related

Confusion JSF Updating Value of Input text in Backing bean

Today, i was solving a small problem in JSF. Actually, i have an InputText on my xhtml page with readyOnly attribute set to true.Requirement was on click of a boolean checkbox, i should make the input text editable, means readyOnly false. The code somewhat seemed like this.
<div class="div-form-col" >
<h:outputLabel value="#{msgs.violationAmount} " for="violationAmt" />
<h:inputText value="#{outpassMBean.violationWebDTO.violationAmount}" id="violationAmt" readonly="true"/>
</div>
<div class="div-form-row">
<div class="div-form-col">
<h:outputLabel value="#{msgs.violationExemptionApplicable} " for="violationExempted" />
<h:selectBooleanCheckbox value="#{outpassMBean.violationWebDTO.violationExemptionApplicable}" id="violationExempted" onchange="makeViolationAmountEditable(this);">
</h:selectBooleanCheckbox>
</div>
</div>
The script of that method was given as below :-
function makeViolationAmountEditable(id){
alert("Ben");
document.getElementById('violationAmt' ).readOnly=false;
alert("Done");
}
Now my first problem was, if i am editing the value in the text field, how i can update the value of violationAmt in backing bean. What can be the best possible way? As i am using PrimeFaces, i came across concept remoteCommand. So here is what i added.
<p:remoteCommand name="makeViolationAmountEditableOnServer" action="#{outpassMBean.makeViolationAmountEditable}" update="amountPanelApplicant"/>
The method at the backing bean level was something like this
public void makeViolationAmountEditable(){
//Set updated value
setUpdatedViolationAmount(violationWebDTO.getViolationAmount());
//Some other code.
}
Problem was that, whenever this code was running, the violation amount in violationWebDTO was the old one, not the one which i was entering after making the input field editable. Though i saw in firebug the updated value was part of request but in the backing bean, however still old value was getting referred. I don't understand why?
My senior told me, you are updating value of readOnly on client side not server side, and updated my code something like this.
<p:outputPanel id="amountPanelApplicant">
<p:outputPanel rendered="#{outpassMBean.violationWebDTO.violationForCmb eq 2 and outpassMBean.violationWebDTO.isViolationExists}">
<p:outputPanel styleClass="div-form twoCol">
<div class="div-form-row">
<div class="div-form-col" >
<h:outputLabel value="#{msgs.violationAmount} " for="violationAmt" />
<h:inputText value="#{outpassMBean.violationWebDTO.violationAmount}" id="violationAmt" readonly="#{outpassMBean.violationAmtEditable}">
</h:inputText>
</div>
<div class="div-form-col">
<h:outputLabel value="#{msgs.outPayTot} " for="totalViolationAmount" />
<h:outputLabel styleClass="readOnly" value="#{outpassMBean.violationWebDTO.totalViolationAmount}" id="totalViolationAmount" />
</div>
</div>
</p:outputPanel>
<p:outputPanel styleClass="div-form twoCol" rendered="#{outpassMBean.outpassApplication.applicationSubType.id eq 2 }" >
<div class="div-form-row">
<div class="div-form-col">
<h:outputLabel value="#{msgs.violationExemptionApplicable} " for="violationExempted" />
<h:selectBooleanCheckbox value="#{outpassMBean.violationWebDTO.violationExemptionApplicable}" id="violationExempted" onchange="makeViolationAmountEditableOnServer();">
</h:selectBooleanCheckbox>
<p:remoteCommand name="makeViolationAmountEditableOnServer" action="#{outpassMBean.makeViolationAmountEditable}" update="amountPanelApplicant"/>
</div>
</div>
</p:outputPanel>
</p:outputPanel>
public void makeViolationAmountEditable(){
if(logger.isDebugEnabled()){
logger.debug("Inside makeViolationAmountEditable...");
}
//setting violation amount editable flag
setViolationAmtEditable(false);
//Preserving original and total amount.
setOriginalViolationAmt(violationWebDTO.getViolationAmount());
setOriginalTotalViolationAmount(violationWebDTO.getTotalViolationAmount());
}
In the above updated code, no javascript called. The readyOnly value is set to true and false from the backing bean itself. After this update, basically the new edited value was updated in the violationWebDTO.
Can someone explain? Why not in the first snapshot? It's not a complete code but i tried to explain the confusion. Any pointers would be helpful.
This is JSF's safeguard against tampered/hacked requests wherein the enduser uses client side languages/tools like HTML or JS to manipulate the HTML DOM tree and/or HTTP request parameters in such way that the outcome of JSF's disabled, readonly or even rendered attribute is altered.
Imagine what would happen if the JSF developer checked an user's role in such a boolean attribute against the admin role like so disabled="#{not user.hasRole('ADMIN')}" and a hacker manipulated it in such way that it isn't disabled anymore for non-admin users. That's exactly why you can only change the mentioned attributes (and the required attribute and all converters, validators, event listeners, etc) on the server side.
This can however be solved in a simpler manner without the need for an additional property, without the <p:remoteCommand> and the additional bean method.
<h:inputText id="violationAmount" ... readonly="#{makeViolationAmountEditable.value}" />
...
<h:selectBooleanCheckbox binding="#{makeViolationAmountEditable}">
<f:ajax render="violationAmount" />
</h:selectBooleanCheckbox>
See also:
Why JSF saves the state of UI components on server?
How does the 'binding' attribute work in JSF? When and how should it be used?.

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

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

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");
}

Resources