SelectOneMenu fire ajax when up or down arrow key is pressed - ajax

I need to fire an ajax call when i hit the up arrow key or the down arrow key when im focused on the selectOneMenu.
Here is my code, i tried only with the up key first (Its not working, and i tried several variations)
<h:selectOneMenu id="id" disabled="#!Bean.disabled}" value="#{Bean.value}" styleClass="style" onkeypress="if (event.keyCode == 38) { onchange(); return false; }">
<f:selectItems id="idItem" value="#{Bean.options}" var="option" />
<f:ajax event="change" execute="#this" render="group"/>
</h:selectOneMenu>
Hint: Tab key is firing it and moving the focus (if the value changed). I dont want the tab key firing it.

Just change the event of your f:ajax to keyup, the change event will not send any ajax request unless your selectOneMenu loses focus (that's also confirmed by your hint "Tab key is firing it and moving the focus ").
That will work like this:
<f:ajax event="keyup" execute="#this" render="group"/>
Update:
I updated my answer following BalusC's comment that the you want the ajax request to be fired only if the up Key or down Key are fired, so i am suggesting you to invoke directly the javascript function that f:ajax calls behind the scenes, So you can add a direct call to jsf.ajax.request(source, event, options) function, you can find more informations about that function here.
In order to use that method you must add the JSF’s built-in JavaScript library in your XHTML files like this:
<h:outputScript library="javax.faces" name="jsf.js"/>
Then change your code like this:
<h:selectOneMenu id="id" disabled="#!Bean.disabled}" value="#{Bean.value}" styleClass="style"
onkeyup="if (event.keyCode == 38 || event.keyCode == 40) { jsf.ajax.request(this, event, { render: 'form:group'}); return false;}">
<f:selectItems id="idItem" value="#{Bean.options}" var="option" />
</h:selectOneMenu>
NB: Please notice that in the render option of the jsf.ajax.request() i specified the exact ClientID of the component you want to render and not only the component id (form is here the id of h:form), if you want to use only the id group you must add prependId="false" to your h:form.

Related

JSF SelectOneMenu onchange, onsubmit cancel reset value

On a JSF SelectOneMenu, I have ajax event onchange, and with an onsubmit with a confirm question, when user abort the change, how could I reset the value on SelectOneMenu back to the original value?
<h:selectOneMenu value="#{bean.selectedFruit}">
<f:selectItems value="#{bean.fruits}"/>
<a:support event="onchange" onsubmit="if(!confirm('Are you sure?'))return false;}" action="#{bean.loadFruitStats}" rerender="body"/>
</h:selectOneMenu>
So on the above example, when user click 'No' on the confirm dialog, the action is not called, and rerender is not called, so the SelctOneMenu is on the updated "fruit" name, not the original one (so the fruit name and the fruit stats info doesnt match). What can I do to synchronize them?
h:selectOneMenu can be reset back to the original value with a help of javascript.
First you will need to define an id to h:selectOneMenu. For example
<h:selectOneMenu id="selFruitId"...>
Add following (self-explanatory) java script to jsf page
var currentValue;
function saveCurrentValue(){
//get html select element
var element=document.getElementById("form:selFruitId");
//saves currently selected value
currentValue=element.value;
}
function areYouSure(){
if(!confirm('Are you sure?')){
//if canceled, restores previously saved value
document.getElementById("form:selFruitId").value=currentValue;
return false;
}
}
Then you need to intercept moment when user tries to change selected value using mouse (onclick event) or keyboard (onkeypress event, for example, left-right-up-down cursor keys or some other key) and save currently selected value for later.
<h:selectOneMenu id="selFruitId"
onclick="saveCurrentValue()" onkeypress="saveCurrentValue()"...>
And, finally, before executing ajax, you need to call function areYouSure() which will, if canceled, restore saved (original) value back to h:selectOneMenu.
<h:selectOneMenu value="#{bean.selectedFruit}" id="selFruitId"
onclick="saveCurrentValue()" onkeypress="saveCurrentValue()">
<f:selectItems value="#{bean.fruits}"/>
<a:support event="onchange" onsubmit="areYouSure()" action="#{bean.loadFruitStats}" rerender="body"/>
</h:selectOneMenu>

AjaxBehaviorEvent from f:ajax inside p:selectOneMenu is sometimes null

I am currently observing a really weird behaviour in the server-side callback of an ajax call from a value change event. Basically, I have a list of p:selectOneMenus on my page and want to make some decisions based on what was selected where. This is the jsf:
<p:outputLabel value="Provider:"/>
<p:selectOneMenu id="bacc_ba_check" value="#{bean.baCheck}" style="width:20em" styleClass="bigDefaultEnabled" disabled="#{controller.readOnlyUser}">
<f:selectItem itemLabel="none" itemValue=""/>
<f:selectItems value="#{bean.baCheckStrings}" />
<f:ajax listener="#{controller.providerChanged}" render="providerlist RPPPanel" onevent="reapplyDefaults" immediate="true"/>
</p:selectOneMenu>
And this is the callback in the controller:
public void providerChanged(AjaxBehaviorEvent event) {
// check for value
if ("Someval".equalsIgnoreCase(...)) {
this.setSomething(true);
} else {
this.setSomething(false);
}
The confusing part is the following: The event is always NULL when I select something else than none from the selectOneMenu. If I reselect 'none' after having selected something else before, the event is correctly set. In the callback, I want to check what the source of the event is so I can set some defaults elsewhere. Does anyone have an idea what could cause this strange behaviour? I really need to know which component fired the event at all times, especially when someone select a non-null value in a dropdown.
Thanks for help or any hints.
(JSF 2.1.7 Mojarra with Primefaces 4.0)

f:ajax don't fired with event "change"

The code:
<h:inputText id="date" value="#{holidayRequestController.dates}">
<f:ajax execute="date" event="change"
listener="#{holidayRequestController.generateDates}"
render="generateDate" />
</h:inputText>
<h:panelGroup id="generateDate" class="span8"> ..</h:panelGroup>
With this code when i using date picker to select a date in from h:inputText, and f:ajax will fire event and populate this date to generateDate component.
But when i change to multiDatePicker, f:ajax don't fired with event "change"(although it work with event "blur", but i have some problem to use "blur").
What should i do to use event "change" for multiDatePicker?
One other question: is there support f:ajax for tag h:inputHidden in jsf?
Thanks for support
That can happen if the change event is actually not fired. That can in turn happen if the input element's value is only manipulated via JavaScript and not via enduser interaction.
Basically, when JavaScript manipulates the value via element.value = newValue, and you want the change event to be fired, then the JavaScript should explicitly call element.change() on the input element being manipulated.
According to $.multiDatesPicker documentation, you can use the onSelect option to hook a function on select. In that function you can then just call element.change(). So, given an input as follows:
<h:inputText ... styleClass="multi-dates" />
then you can achieve it as follows:
$(".multi-dates").multiDatesPicker({
onSelect: function() {
$(this).change();
}
});

selectOneMenu ajax events

I am using an editable primefaces selectOneMenu to display some values. If the user selects an item from the List a textarea should be updated. However, if the user types something in the selectOneMenu, the textarea should not be updated.
I thought I could work this with ajax event out. However, I don't know which event I can use here. I only know the valueChange event. Are there any other events, like onSelect or onKeyUp?
Here is my code:
<p:selectOneMenu id="betreff" style="width: 470px !important;"
editable="true" value="#{post.aktNachricht.subject}">
<p:ajax event="valueChange" update="msgtext"
listener="#{post.subjectSelectionChanged}" />
<f:selectItems value="#{post.subjectList}" />
</p:selectOneMenu>
<p:inputTextarea style="width:550px;" rows="15" id="msgtext"
value="#{post.aktNachricht.text}" />
The PrimeFaces ajax events sometimes are very poorly documented, so in most cases you must go to the source code and check yourself.
p:selectOneMenu supports change event:
<p:selectOneMenu ..>
<p:ajax event="change" update="msgtext"
listener="#{post.subjectSelectionChanged}" />
<!--...-->
</p:selectOneMenu>
which triggers listener with AjaxBehaviorEvent as argument in signature:
public void subjectSelectionChanged(final AjaxBehaviorEvent event) {...}
I'd rather use more convenient itemSelect event. With this event you can use org.primefaces.event.SelectEvent objects in your listener.
<p:selectOneMenu ...>
<p:ajax event="itemSelect"
update="messages"
listener="#{beanMB.onItemSelectedListener}"/>
</p:selectOneMenu>
With such listener:
public void onItemSelectedListener(SelectEvent event){
MyItem selectedItem = (MyItem) event.getObject();
//do something with selected value
}
Be carefull that the page does not contain any empty component which has "required" attribute as "true" before your selectOneMenu component running.
If you use a component such as
<p:inputText label="Nm:" id="id_name" value="#{ myHelper.name}" required="true"/>
then,
<p:selectOneMenu .....></p:selectOneMenu>
and forget to fill the required component, ajax listener of selectoneMenu cannot be executed.
You could check whether the value of your selectOneMenu component belongs to the list of subjects.
Namely:
public void subjectSelectionChanged() {
// Cancel if subject is manually written
if (!subjectList.contains(aktNachricht.subject)) { return; }
// Write your code here in case the user selected (or wrote) an item of the list
// ....
}
Supposedly subjectList is a collection type, like ArrayList. Of course here your code will run in case the user writes an item of your selectOneMenu list.

JSF f:ajax listener not called

I am trying to have an h:inputText switch out with a different one when an h:commandButton is clicked. To do this, I am trying to tie an f:ajax command with the h:commandButton, with the listener setting a value on the bean (deciding which one to display), and re-rendering the area.
I have tried using listener on the f:ajax, actionListener on the h:commandButton, action on the h:commandButton with execute on the f:ajax. Nothing worked. The mothed I am trying to call is not being called at all - there is no println (see what follows).
The panelGroup is being re-rendered, which is why I need the onevent attribute that re-attaches some JavaScript hint text based on the title (I had an earlier question involving this).
The method I am trying to call:
public void morePressed(AjaxBehaviorEvent e) {
easySearch = !easySearch;
System.out.println("Made it!");
}
The JSF segment that is not working (note the last h:commandButton is trying to re-render the panelGroup):
<h:form>
<h:panelGroup id="switchSearchTexts">
<h:inputText accesskey="s" alt="Search" id="searchBoxPeople" title="Search Plebeians" valueChangeListener="#{peopleBean.simplePersonQuery}" size="25" rendered="#{peopleBean.easySearch}">
<f:ajax render="peopleDataTable" event="keyup" />
</h:inputText>
<h:inputText accesskey="s" alt="Search First Name" id="searchBoxFN" title="Search First Name" size="25" rendered="#{!peopleBean.easySearch}">
<f:ajax render="peopleDataTable" event="keyup" />
</h:inputText>
</h:panelGroup>
<div id="expandBox">
<h:inputText id="searchBoxLN" alt="Search Last Name" styleClass="hideToggle" title="Search Last Name" size="25" />
<h:inputText id="searchBoxAddress" alt="Search Address" styleClass="hideToggle" title="Search Address" size="25" />
</div>
<h:commandButton type="button" styleClass="moreButtonAsText" id="moreButtonAsText" value="▸More">
<f:ajax listener="#{peopleBean.morePressed}" render="switchSearchTexts" event="click" onevent="callFunctionAjaxRequest" />
</h:commandButton>
This is the JavaScript (jQuery) that I attach to the More button on pageload. I give it not because I think it could help, but I don't know if this could interfere with the ajax listener in any way:
$(function() {
textboxHint();
$('input[id$="moreButtonAsText"]').toggle(function(e) {
$(this).prop('value', '\u25c2Less');
$(".hideToggle").show(300);
}
, function () {
$(this).prop('value', '\u25b8More');
$(".hideToggle").hide(100);
$('input[id$="searchBoxAddress"]').prop('value', function() {
return $(this).prop('title');
});
$('input[id$="searchBoxAddress"]').blur();
});
});
I have no idea. As I said, I have tried actionListener on h:commandButton with various appraoches there, as well as various approaches to the listener on the ajax. Can anybody see why the listener does not work?
Update:
What I ended up doing, before having an answer, is converting everything to display and hide based on JavaScript, with stuff I needed hidden if they didn't have javascript initially hidden, etc.
However I need the f:ajax elsewhere, now.
The solution is to take out event="click" on the h:commandButton. I still do now know why this was causing it to break, but hey, whatever works.
I had an issue like this. It turned out that an inputText somewhere had a value="#{something.something}" where the property wasn't settable. The exception wasn't being reported anywhere. I had to put a breakpoint on Exception and all subclasses to find it.
Do you really have a function named callFunctionAjaxRequest in your js code? cause if not it may cause the button not to work (because its being referenced to a not existing function) ,
look at the firebug for a possible errors...
try this version of your command button (event="click" can be removed too... and self execute too)
<h:commandButton type="button" styleClass="moreButtonAsText" id="moreButtonAsText" value="More">
<f:ajax listener="#{peopleBean.morePressed}" render="switchSearchTexts" />
</h:commandButton>
Another thing , in your ajax calls of the upper input texts you got reference to searchBoxPeople twice (instead to searchBoxFN in the second f:ajax), fix it cause otherwise when working with searchBoxFN its f:ajax will try to execute an element that its not being rendered ... (can cause serious issues...)
p.s prependId="false" in your h:form will simplify your selectors in jQuery...
The issue is that the managed bean needs to be set up with the right signature event as an input param. Through lots of testing, I was trying to use the same class taking an AjaxBehaviorEvent. As in the same example on the previous forum.
when I declared an ActionListener event (compliant with the button jsf action), the bean is executed!
I had the same problem and followed your example to help me exactly. I simply (20 hrs) fixed this by including the following in my bean:
The first one now gets fired!
public void actionListener(ActionEvent actionEvent) {
// Add event code here...
System.out.println("Made it!");
}
public void morePressed(AjaxBehaviorEvent e) {
System.out.println("Made it!");
}

Resources