SelectOneMenu ajax does not work - ajax

I'm working on project base on primefaces....
I'm trying to do as follows: JSF
<p:selectOneMenu id = "activeTin"
panelStyle = "width:280px"
effect = "fade"
var = "t"
value = "#{homeBean.value}"
itemValue = "#{data}">
<p:ajax process = "#this"
event = "change"
listener = "#{homeBean.changeActiveTin}"
update = "#this"/>
<f:selectItems value = "#{homeBean.valueList}"
var = "data"
itemLabel ="#{data.companyTinId}"></f:selectItems>
</p:selectOneMenu>
selectOneMenu dose not enter ajax listener
What's wrong in my code?

Related

PrimeFaces ajax update is not triggered when required input field becomes empty

I am using JSF with PrimeFaces with fields like below.
<p:outputLabel for="vehicle" value="#{msg['vehicle.text']}" />
<p:autoComplete id="vehicle" value="#{newCtrlr.vehicleId.vehicle}" autocomplete="true" scrollHeight = "200" required = "true"
completeMethod="#{newCtrlr.vehicle_AutoComplete}" minQueryLength = "2">
<p:ajax event="itemSelect" listener = "#{newCtrlr.onVehicleChange}" update = "market" />
<p:ajax event="change" listener = "#{newCtrlr.onVehicleChange}" update = "market" />
</p:autoComplete>
<p:outputLabel for="market" value="#{msg['market.text']}" />
<p:inputText id="market" value="#{newCtrlr.market.marketName}"
readonly = "#{empty newCtrlr.vehicleId.vehicle ? 'true' :'false' }" />
In the above code, if the vehicle value is entered, the market should be made editable. If the vehicle value is cleared, the market should become readonly. Now since the vehicle input is 'required', the ajax update is not triggered and so the market remains enabled. If I remove the 'required' on Vehicle, everything works fine. I would like to know if there is a way to make the inputText required as well as trigger the ajax update when the value is changed to empty/null in the required field.
First of all, this behavior is default JSF behavior: If the input in invalid, it is not written to the model.
So you have to change this behavior manually, for example with an Event-Listener.
Add the following method to your Backing-Bean:
public void setModelValueToNullIfValidationFailed(ComponentSystemEvent event) throws AbortProcessingException {
UIInput input = (UIInput) event.getComponent();
if (input.isValid()) {
return;
}
input.getValueExpression("value").setValue(FacesContext.getCurrentInstance().getELContext(), null);
}
This method checks if the validation of the component has failed. If so the model value is set to null.
Add f:event to your p:autoComplete:
<p:autoComplete ...>
...
<f:event type="postValidate" listener="#{newCtrlr.setModelValueToNullIfValidationFailed}" />
</p:autoComplete>

Creating Dropdown Box using AJAX with JSF/Primefaces

I am trying to create a simple dropdown box using Ajax and JSF 2.0/primeface. Based on First Dropdown selection second dropdown box is populated using AJAX call.
When I select first drop down it correctly populated the second dropdown box based on the Ajax call. But When I make selection in the second dropdown and click the button {which basically submit the form for some action}, It give error message
"formViewBusinessCode:selectedBusinessCode: Validation Error: Value is not valid"
When I check in console that is says the value for "selectedBusinessCode"{Id of second dropdown} is null. I am puzzled becuase it populates correctly but only after selection it gives error that value is not valid (basically null), Why the selected value is not reaching to the bean? Can someone please point what I am missing here, TIA
xhtml code is as below
<h:outputText styleClass="outputText" value="#{constant.businessCodeGroup}"></h:outputText>
<h:selectOneMenu id="selectedBusinessCodeGroup" value="#{viewBusinessCodeBean.selectedBusinessCodeGroup}" >
<f:selectItem itemValue="SELCT" itemLabel="Select Business Code Group" />
<f:selectItems value="#{viewBusinessCodeBean.businessCodeGroupList}" />
<p:ajax listener="#{viewBusinessCodeBean.getOnlyBusinessCodeListByAjaxCall}" event="change" update="selectedBusinessCode" process="#this"/>
</h:selectOneMenu>
<h:outputText styleClass="outputText" value="#{constant.businessCode}"></h:outputText>
<h:selectOneMenu id="selectedBusinessCode" value="#{viewBusinessCodeBean.selectedBusinessCode}">
<f:selectItem itemValue="SELCT" itemLabel="Select Business Code" />
<f:selectItems value="#{viewBusinessCodeBean.businessCodeList}" itemLable="#{viewBusinessCodeBean.businessCodeList.getlable}"
itemValue="#{viewBusinessCodeBean.businessCodeList.getValue}" />
</h:selectOneMenu>
<h:commandButton value="View" action="#{viewBusinessCodeBean.getOnlyBusinessCodeDescription}"></h:commandButton>
The bean coding is as below. it is a #ManagedBean
To Populate First Dropdown box
public ViewBusinessCodeBean() {
logger.entering(CLASS_NAME);
this.businessCodeGroupList = new ArrayList<SelectItem>();
List<String>tempBusinessCodeList = new BusinessCodeTableServices().getBusinessCodeGroupList();
Iterator<String>iterator = tempBusinessCodeList.iterator();
while(iterator.hasNext()){
String businessCodeGroup = iterator.next();
logger.debug(businessCodeGroup);
SelectItem item = new SelectItem(businessCodeGroup);
businessCodeGroupList.add(item);
}
logger.exiting(CLASS_NAME);
}
Ajax Call Method which populated second dropdown
public void getOnlyBusinessCodeListByAjaxCall() {
this.businessCodeList = new ArrayList<SelectItem>();
List<String>tempBusinessCodeList = new BusinessCodeTableServices().getOnlyBusinessCodeList(getSelectedBusinessCodeGroup());
Iterator<String>iterator = tempBusinessCodeList.iterator();
while(iterator.hasNext()){
String businessCode = iterator.next();
SelectItem item = new SelectItem(businessCode,businessCode,businessCode);
businessCodeList.add(item);
}
}
Your bean is apparently in the request scope. A request scoped bean is reconstructed on every request with all properties set to default. Your validation error is caused because businessCodeList property has become null/empty during the request of processing the form submit.
Putting the bean in the view scope should fix this problem.
See also:
Validation Error: Value is not valid
How to choose the right bean scope?

strange jsf panelgroup binding -> h:selectOneMenu validation Exception

lets start simple:
- an easy search form
- two h:selectOneMenu components are declared inside a form
- the second selectOneMenu, is refreshed base on selecting an item of the first selectOneMenu (with ajax)
For this, i use a central Bean in request scope, because the two selectOneMenus are declared on many other pages, so i dont need to define the two following methods multiple times:
pageSupport:
#SuppressWarnings("unchecked")
public List<BranchenRubrik> getLst_branchenRubrik() {
if(lst_branchenRubrik == null) {
Session session = hibernate.InitSessionFactory.getInstance().getCurrentSession();
Transaction tx = session.beginTransaction();
this.lst_branchenRubrik = session.createQuery("from BranchenRubrik").list();
tx.commit();
}
return lst_branchenRubrik;
}
// Loading Subkats with parameter
#SuppressWarnings("unchecked")
public List<BranchenRubrikSub> getBranchenRubrikSub(long p_parent) {
List<BranchenRubrikSub> lst_branchenRubrikSub = new ArrayList<BranchenRubrikSub>();
if(p_parent > 0) {
Session session = hibernate.InitSessionFactory.getInstance().getCurrentSession();
Transaction tx = session.beginTransaction();
lst_branchenRubrikSub = session.createQuery("from BranchenRubrikSub BRS WHERE BRS.parentRubrik.id = :p1").setLong("p1",p_parent).list();
tx.commit();
}
return lst_branchenRubrikSub;
}
VDL:
<p:selectOneMenu value="#{searchBean2.fvz.branchenRubrikID}">
<f:selectItem itemLabel="Bitte wählen" itemValue="0"/>
<f:selectItems value="#{pageSupport.lst_branchenRubrik}" var="rubrik" itemValue="#{rubrik.id}" itemLabel="#{rubrik.rubrik}"/>
<f:ajax render="uiBranchenSubKat"/>
</p:selectOneMenu>
<h:outputText value="Unterkategorie" />
<p:selectOneMenu id="uiBranchenSubKat" value="#{searchBean2.fvz.branchenRubrikSubID}">
<f:selectItems value="#{pageSupport.getBranchenRubrikSub(searchBean2.fvz.branchenRubrikID)}" var="brs" itemLabel="#{brs.rubrik}" itemValue="#{brs.id}"/>
</p:selectOneMenu>
this works fine, i can submit the form and all data are saved and will be re-displayed.
Now, i want to include an h:panelGroup with binding to a methode, which build a pagination menue.
If i include the h:panelGroup binding="#{searchBean2.paginationMenu}"/> then, i cant submit the form, because it says that the value for the second h:selectOneMenu is not valid.
if i remove the "h:panelGroup binding" all working as expected.
The h:panelgroup can also binded to an empty methode "return new HtmlPanelGroup()"
then, the error occurs again.
looks like, that the component binding, breaks some validation.
thanks for your time

Multiple onClick events

I have a JSF page, a drop down where values are getting fetched from service.
Default is "Select from Drop Down" and a datePicker and a submit button.
I need to apply JS/AJAX validation here.
If a user clicks on Submit button without chosing any value from the drop down and the date. It should first diplay a message,
1) If none chosen, first show a message - Please select a value from drop down.
2) if the value is selected from the drop down and date has not been selected It should display a message " select a date".
3) if the date is selected and value is not selected from the drop down It should display a message " select a value from the drop down".
Both validation should be done on a single click on submit button.
Currently it's just checking if date is not selected. onclick event code is mentioned below.
Drop Down
<h:selectOneMenu id="valueList" value="#bean.values">
<f:selectItem itemValue="Select Action" itemLabel="Select Action" />
<f:selectItems value="#{sampleService.sampleMethod}"
var="SampleVar" itemValue="#{SampleVar}"
itemLabel="#{SampleVar}">
</f:selectItems>
</h:selectOneMenu>
Submit button
<ui:define name="actions">
----h:inputHidden id="getAllDates"
value="#{serviceMethod.getAllDates}"-----
<h:commandButton styleClass="inputbutton" valuGenerate" id="export"
action="#{generate.someReport}" onclick="saveDate(); />
</ui:define>
Passing all selected dates in hidden.
OnClick event this js function is written in another file.
onclick="saveDate();"
function saveDate() {
var dates = $('#selectDates').datepick('getDate');
var datesValue = '';
if(dates==null || dates=="undefined"){
alert("Select Dates");
return false;
}
if(dates!=null){
// store in an array and return true
}
Currently page is getting refreshed on every click on Submit button and alert message gets displayed only for date.
Can anybody help me in applying ajax call on submit button and displaying validation messages?
You're thinking too much in the JavaScript direction. Use JSF provided facilities. Use the required attribute to specify required inputs. Use requiredMessage attribute to specify the validation message. Use <h:message> to display the validation messages. Use <f:ajax> to submit (and validate) data by ajax.
So, this should do:
<h:selectOneMenu id="action" binding="#{action}" value="#{bean.action}" required="true" requiredMessage="Please select action">
<f:selectItem itemValue="#{null}" itemLabel="Select Action" />
<f:selectItems value="#{bean.actions}" />
<f:ajax execute="#this" render="actionMessage date" />
</h:selectOneMenu>
<h:message id="actionMessage" for="action" />
<x:yourDatePickerComponent id="date" value="#{bean.date}" required="#{not empty action.value}" requiredMessage="Please select date">
<f:ajax execute="#this" render="dateMessage" />
</x:yourDatePickerComponent>
<h:message id="dateMessage" for="date" />
(I have no idea what component you're using as date picker, just replace x:yourDatePickerComponent accordingly)
you don't need ajax :
function save() {
var validated = true;
var dates = $('#selectDates').datepick('getDate');
var datesValue = '';
var message;
if(dates==null || dates=="undefined"){
alert("Select Dates");
message = "message1";
validated = false;
return false;
}
if( $('#idOfDropDown').val() != ''){
message = "message2";
validated = false;
return false;
}
if(!validated){
// preveent thr form from submitting
return false;
}
}

Ajax Listener event valueChange seems to be firing onClick instead of onChange

I have a nested list of Questions that I'd like to display. Initially, I'm displaying the Level 1 questions and then subquestions are displayed based on the users answers to the their parent question. All questions have a radio button and some questions have an input box for additional information that is shown when user selects "Yes"
Here is my JSF code with nested dataTables. Please note that I have pulled out formatting of these questions in order to simply the question on the forum, so these may look "unpretty" if you copy this code into your own environment and run the code:
<h:dataTable id="questionTable" var="q" value="#{generalQuestionBean2.questions.questions}">
<h:column><h:panelGroup id="questionGrp">
#{q.question} <h:selectOneRadio value="#{q.answer}">
<f:selectItem itemValue="1" itemLabel="Yes"/>
<f:selectItem itemValue="0" itemLabel="No"/>
<f:ajax event="valueChange" execute="#form"
render="questionGrp"
listener="#{generalQuestionBean2.reset}"/>
</h:selectOneRadio> <h:inputText value="#{q.addnInfo}"
rendered="#{q.answer eq '1' and q.field ne 'otherCov'}"></h:inputText>
<h:panelGroup id="questionGrpSubs" rendered="#{q.addnQuestions ne null and q.answer eq '1'}">
<h:dataTable id="subQuestionTable" var="subq" value="#{q.addnQuestions}">
<h:column><h:panelGroup id="subQuestionGrp">
->#{subq.question} <h:selectOneRadio id="answer" value="#{subq.answer}">
<f:selectItem itemValue="1" itemLabel="Yes"/>
<f:selectItem itemValue="0" itemLabel="No"/>
<f:ajax event="valueChange" execute="#form"
render="subQuestionGrp"
listener="#{generalQuestionBean2.reset}"/>
</h:selectOneRadio><h:inputText value="#{subq.addnInfo}"
rendered="#{subq.answer eq '1' and subq.field ne 'voluntaryComp' and subq.field ne 'uslh'}"></h:inputText>
<h:panelGroup id="questionGrpSubs2" rendered="#{subq.addnQuestions ne null and subq.answer eq '1'}">
<h:dataTable id="sub2QuestionTable" var="sub2q" value="#{subq.addnQuestions}">
<h:column><h:panelGroup id="sub2QuestionGrp">
-->#{sub2q.question} <h:selectOneRadio id="answer" value="#{sub2q.answer}">
<f:selectItem itemValue="1" itemLabel="Yes"/>
<f:selectItem itemValue="0" itemLabel="No"/>
<f:ajax event="valueChange" execute="#form"
render="sub2QuestionGrp"
listener="#{generalQuestionBean2.reset}"/>
</h:selectOneRadio><h:inputText value="#{sub2q.addnInfo}"
rendered="#{sub2q.answer eq '1'}"></h:inputText>
</h:panelGroup></h:column>
</h:dataTable></h:panelGroup>
</h:panelGroup></h:column>
</h:dataTable></h:panelGroup>
</h:panelGroup></h:column>
</h:dataTable>
Here is the code for the reset function on the backing bean:
private void reset(AjaxBehaviorEvent event) {
FacesContext context = FacesContext.getCurrentInstance();
String id = event.getComponent().getClientId(context);
String[] tokens = id.split("[:]+");
int qId = -1;
int subqId = -1;
int sub2qId = -1;
for (int i = 0; i < tokens.length; i++) {
if(tokens[i].equals("questionTable"))
qId = Integer.parseInt(tokens[i+1]);
if(tokens[i].equals("subQuestionTable"))
subqId = Integer.parseInt(tokens[i+1]);
if(tokens[i].equals("sub2QuestionTable"))
sub2qId = Integer.parseInt(tokens[i+1]);
}
Question q = questions.getQuestion(qId);
Question processQ = q;
String defaultSubAnswer = getDefaultSubAnswer(q.getField());
Question subq;
Question subq2;
if(subqId > -1) {
subq = q.getAddnQuestions().get(subqId);
processQ = subq;
if(sub2qId > -1) {
subq2 = subq.getAddnQuestions().get(sub2qId);
processQ = subq2;
}
}
resetValue(processQ, defaultSubAnswer);
}
private void resetValue(Question q, String defaultSubAnswer) {
q.setAddnInfo("");
if(q.getAddnQuestions() != null) {
for (int i = 0; i < q.getAddnQuestions().size(); i++) {
Question subq = q.getAddnQuestions().get(i);
subq.setAnswer(defaultSubAnswer);
resetValue(subq, defaultSubAnswer);
}
}
}
Here is the problem:
The ajax event should default to "valueChange". If I click on "Yes" and then "Yes" again, the ajax call should not happen, correct? But it is, as the Additional Info box is clearing out based on the reset function.
I had originally tried adding a condition to the reset function to check the value of the button that was clicked and only reset the addnInfo value and subquestions if the answer is "0" (No). But this was causing issues with the rendering as the ajax call would render the input box and subquestions to hide and the value would be held onto on the front end, even though they're reset on the backing bean. When they re-rendered to the front in, the value that was held onto shows up instead of the value in the backing bean.
Another attempt was using a ValueChangeListener for the reset of the values. But this still has the same issue with the value being held onto when re-rendering.
I have tried 3 different approaches (listed above) and all have failed. I'm open to hearing a solution to any of these or possibly another solution. Keep in mind that formatting limitations by the users leaves me with less options to work with.
Ajax Listener event valueChange seems to be firing onClick instead of onChange
That's indeed the default valueChange event which is been used by the radio buttons and checkboxes which are genreated by the respective JSF components. Check the generated HTML source and you'll see that it's hooked to onclick. The reason why JSF does that by default is clear for checkboxes, but at first sight not entirely clear for radio buttons as they cannot be unticked anyway. The real reason is that it's done in order to ensure IE6/7 compatibility as onchange wouldn't be fired on 1st click in that browser.
If you don't care about IE6/7 users (whose distribution is however stongly decreasing lately), then change it to event="change" instead.
<f:ajax event="change" ... />
This way JSF will generate the event handler on onchange instead.
Update: you could use jQuery's .on('change') function binder which will fix the IE6/7 misbehaviour on the change event. Include the following in <h:head> if you're not already using jQuery:
<script src="http://code.jquery.com/jquery-latest.min.js"></script>
and execute this function on load:
$(function() {
$(':radio').each(function() {
var handler = this.onclick;
this.onclick = null;
$(this).on('change', handler);
});
});
This will basically for every radio button move the JSF-generated onclick attribute to change event handler which is managed by jQuery so that it works consitent in all browsers, including IE6/7.
We can of course also do it with plain JS, but that would require lot of boilerplate and cross browser sensitive code.

Resources