Javascript error in XHTML page in JSF 2 - jsf

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

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

How do PrimeFaces Selectors as in update="#(.myClass)" work?

I don't understand how PrimeFaces selectors (PFS) work.
<h:outputText value="#{bean.text1}" styleClass="myClass" />
<p:commandButton update="#(.myClass)" />
I can use it. And I think it's a fantastic tool although it doesn't function always for me. The .myClass is client side jQuery selector. How does JSF on server side know what to update?
I can understand how normal JSF ID selectors work.
<h:outputText value="#{bean.text1}" id="textId" />
<p:commandButton update="textId" />
The textId references an ID of component in the component tree as defined in XHTML file in server side. So I can understand how JSF finds the right component.
But if you are using primefaces selectors, the client side jQuery selectors are used. How does JSF know which component has to be updated? Sometimes I have problems with PFS. It doesn't seem to function always for me. Is there something what you should keep in mind if you are using PFS?
You probably already know that PrimeFaces is using jQuery under the covers. PrimeFaces Selectors are based on jQuery. Anything which you specify in #(...) will be used as jQuery selector on the current HTML DOM tree. For any found HTML element, which has an ID, exactly this ID will ultimately be used in the update.
Basically, for a update="#(.myclass)", PrimeFaces will under the covers roughly do this:
var $elements = $(".myclass");
var clientIds = [];
$.each($elements, function(index, element) {
if (element.id) {
clientIds.push(":" + element.id);
}
});
var newUpdate = clientIds.join(" "); // This will be used as `update` instead.
So, in case of e.g.
<h:form id="formId">
<h:outputText id="output1" styleClass="myclass" ... />
<h:outputText styleClass="myclass" ... />
<h:outputText id="output3" styleClass="myclass" ... />
</h:form>
this command button update
<p:commandButton ... update="#(.myclass)" />
will end up with exactly the same effect as
<p:commandButton ... update=":formId:output1 :formId:output3" />
Note that this also works for autogenerated IDs. I.e. the <h:form id> is not mandatory.
Sometimes I have a problems with PFS. Is there something what you are should keep in mind if you are using PFS ?
It can happen that you selected "too much" (e.g. #(form) doesn't select current form, but all forms, exactly like $("form") in jQuery!), or that you actually selected nothing (when the desired HTML DOM element has actually no ID). Investigating element IDs in the HTML DOM tree and the request payload in the HTTP traffic monitor the should give clues.
The desired elements in the HTML DOM tree must have an (autogenerated) ID. The javax.faces.partial.render request parameter in the HTTP traffic monitor must contain the right client IDs. The element's rendered attribute in the JSF component tree must evaluate true during update. Etcetera.
In your particular example, the <h:outputText> won't end up in the generated HTML output with any ID. Assigning it an id should solve your problem with updating it.
So, this example won't work
<h:form>
<h:outputText value="#{bean.text1}" styleClass="myClass" />
<p:commandButton value="Update" update="#(.myClass)" />
</h:form>
but this example will work (note that assigning the form an ID is not necessary):
<h:form>
<h:outputText id="myText" value="#{bean.text1}" styleClass="myClass" />
<p:commandButton value="Update" update="#(.myClass)" />
</h:form>

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.

Can we create textbox right next to selectonemenu component when we fire selectoneMenu valueChangeListener event

want to create textbox on the fly is it possible?
Select Report to run:
<h:selectOneMenu value="#{reportBean.selectReport}">
<f:selectItems value = "#{reportBean.allReports}" />
<f:ajax listener="#{reportBean.getReqID}" render="reqID"> </f:ajax>
</h:selectOneMenu>
Seems like you want to show/hide the <h:inputText> based on the selected value on your <h:selectOneMenu>. Yes, this can be easily achieved with plain JSF.
Note that if you use set the rendered attribute as false the component won't appear in the component tree, so there will be no way it can't be referenced for any call (not even ajax calls). In order to update it, you should wrap the component inside another component like <h:panelGroup> and render the wrapper. Basic example:
<h:form id="frmRep">
<h:selectOneMenu value="#{reportBean.selectReport}">
<f:selectItems value = "#{reportBean.allReports}" />
<!--
assuming your reportBean.getReqID method will change the value of
reportBean.showReqID attribute to render/not render it and works well
-->
<f:ajax listener="#{reportBean.getReqID}" render="pnlRepName" />
</h:selectOneMenu>
<h:panelGroup id="pnlRepName">
<h:inputText id="reqID" rendered="#{reportBean.showReqID}"
value="#{reportBean.reportName}" />
<h:panelGroup>
</h:form>
For this specific requirement instead, I won't recommend using an ajax call since it has to go to the server to only check if the component should or should not be showed to the user. I would opt for a JavaScript solution to handle this just on client side.

How populate a select tag in HTML to JSF 2?

I have this code which works fine in HTML as you can see, but how get the values of the <select /> tag to insert in my bean ?
Something like this:
<h:outputLabel for="state" value="State:" />
<h:selectOneMenu id="state" value="#{bean.state}" />
I'm trying a lot of things but nothing so far.
Any idea ?
This isn't going to work. JSF needs to know about all of the dropdown items.
Either use a plain HTML <select> element instead of <h:selectOneMenu> and grab the submitted value by #ManagedProperty or <f:viewParam>, or port that JS code to JSF backing bean code so that you can use <f:selectItems>. You can use <f:ajax> to fill and render the 2nd dropdown.
The Javascript functions seem to take the ids of the selects.
If you do <h:form prependId="false"> and <h:selectOneMenu id="city" then "city" will be the id of the select rendered by JSF. Just pass that ids to the functions.
<h:form prependId="false">
<h:selectOneMenu id="city" value="#{bean.selectedCity}">
</h:selectOneMenu>
<h:selectOneMenu id="state" value="#{bean.selectedState}">
</h:selectOneMenu>
</h:form>
<script language="JavaScript" type="text/javascript" charset="utf-8">
$(document).ready(function() {
new dgCidadesEstados({
cidade: document.getElementById('city'),
estado: document.getElementById('state')
});
});
</script>
You need to use <h:selectItems> tag. A nice introduction is here and here .
I have an stupid (or funny) idea when i integrate CKEditor into JSF (take a look, it is wonderful).
Thus, CKEditor does not support JSF fully, but it supports HTML and JS (jQuery) themselves. When editing in CKEditor, it create other tags for user to input on it, and when user submit information to server, nothing found in that. So I created a <h:inputTextArea value="#{bean.textEditor}"/> and when user submit, it run a script to set its value to that <h:inputTextArea/> :)
Back to your question, i would fire a JS script to do that trick :).You can use <h:inputHidden value=#{bean.city}/> and onclick event on submit button or something like that to do that trick :). But in this case, you have to validate data yourself to make sure that this information is vaild.

Resources