Reputation: 313
I have the following SelectOneRadio:
<p:selectOneRadio id="sex" tabindex="3" value="#{signUp.gender}" required="true">
<f:selectItem itemLabel="Male" itemValue="M" />
<f:selectItem itemLabel="Female" itemValue="F" />
</p:selectOneRadio>
Although the tabindex of the next element in my form is 4, when I tab to the "sex" component, and select any of the selectItem with either the space bar or with a mouse click, when I press the tab key again, the focus goes to the element with tabindex = 1, instead of the next one. How can I fix this?
I'm using primefaces 4.0
Thanks!
Upvotes: 3
Views: 1334
Reputation: 4423
I was able to reproduce the error using Primfaces showcase and I've also found a bug regarding the spacebar selection which is still opened.
As a work around you can override Primefaces default SelectOneRadio widget and make the required changes. To test that approach I've created a file called customradio.js with the following content:
PrimeFaces.widget.SelectOneRadio = PrimeFaces.widget.BaseWidget.extend({
init: function(cfg) {
this._super(cfg);
//custom layout
if (this.cfg.custom) {
this.inputs = $('input:radio[name="' + this.id + '"]:not(:disabled)');
this.outputs = this.inputs.parent().next('.ui-radiobutton-box:not(.ui-state-disabled)');
this.labels = $();
this.icons = this.outputs.find('.ui-radiobutton-icon');
//labels
for (var i = 0; i < this.outputs.length; i++) {
this.labels = this.labels.add('label[for="' + this.outputs.eq(i).parent().attr('id') + '"]');
}
}
//regular layout
else {
this.outputs = this.jq.find('.ui-radiobutton-box:not(.ui-state-disabled)');
this.inputs = this.jq.find(':radio:not(:disabled)');
this.labels = this.jq.find('label:not(.ui-state-disabled)');
this.icons = this.jq.find('.ui-radiobutton-icon');
}
this.checkedRadio = this.outputs.filter('.ui-state-active');
this.bindEvents();
//pfs metadata
this.inputs.data(PrimeFaces.CLIENT_ID_DATA, this.id);
},
bindEvents: function() {
var $this = this;
this.outputs.on('mouseover.selectOneRadio', function() {
$(this).addClass('ui-state-hover');
})
.on('mouseout.selectOneRadio', function() {
$(this).removeClass('ui-state-hover');
})
.on('click.selectOneRadio', function() {
var radio = $(this),
input = radio.prev().children(':radio');
if (!radio.hasClass('ui-state-active')) {
$this.unselect($this.checkedRadio);
$this.select(radio);
input.trigger('click');
input.trigger('change');
}
else {
input.trigger('click');
}
});
this.labels.on('click.selectOneRadio', function(e) {
var target = $(PrimeFaces.escapeClientId($(this).attr('for'))),
radio = null;
//checks if target is input or not(custom labels)
if (target.is(':input'))
radio = target.parent().next();
else
radio = target.children('.ui-radiobutton-box'); //custom layout
radio.trigger('click.selectOneRadio');
console.log("click.selectOneRadio");
e.preventDefault();
});
this.inputs.on('focus.selectOneRadio', function() {
var input = $(this),
radio = input.parent().next();
if (input.prop('checked')) {
radio.removeClass('ui-state-active');
}
radio.addClass('ui-state-focus');
})
.on('blur.selectOneRadio', function() {
var input = $(this),
radio = input.parent().next();
if (input.prop('checked')) {
radio.addClass('ui-state-active');
}
radio.removeClass('ui-state-focus');
})
.on('keydown.selectOneRadio', function(e) {
var input = $(this),
currentRadio = input.parent().next(),
index = $this.inputs.index(input),
size = $this.inputs.length,
keyCode = $.ui.keyCode,
key = e.which;
switch (key) {
case keyCode.UP:
case keyCode.LEFT:
var prevRadioInput = (index === 0) ? $this.inputs.eq((size - 1)) : $this.inputs.eq(--index),
prevRadio = prevRadioInput.parent().next();
input.blur();
$this.unselect(currentRadio);
$this.select(prevRadio);
prevRadioInput.trigger('focus').trigger('change');
e.preventDefault();
break;
case keyCode.DOWN:
case keyCode.RIGHT:
var nextRadioInput = (index === (size - 1)) ? $this.inputs.eq(0) : $this.inputs.eq(++index),
nextRadio = nextRadioInput.parent().next();
input.blur();
$this.unselect(currentRadio);
$this.select(nextRadio);
nextRadioInput.trigger('focus').trigger('change');
e.preventDefault();
break;
case keyCode.SPACE:
if (!currentRadio.hasClass('ui-state-active')) {
$this.unselect($this.checkedRadio);
$this.select(currentRadio);
input.trigger('change');
}
break;
}
});
if (this.cfg.behaviors) {
PrimeFaces.attachBehaviors(this.inputs, this.cfg.behaviors);
}
},
unselect: function(radio) {
radio.prev().children(':radio').prop('checked', false);
radio.removeClass('ui-state-active').children('.ui-radiobutton-icon').removeClass('ui-icon ui-icon-bullet');
},
select: function(radio) {
this.checkedRadio = radio;
radio.addClass('ui-state-active').children('.ui-radiobutton-icon').addClass('ui-icon ui-icon-bullet');
radio.prev().children(':radio').prop('checked', true).focus();
}
});
The major changes were:
I hope that can help you.
Upvotes: 2