TL;DR: how do I implement a "select" helper so that once an element from a set is selected, keypress
events are fired with their target
equal to the element, not body
?
I'm trying to make a number of elements be "selectable": once a user clicks one of them, that one gets selected, and also it should be possible to navigate between them using arrows. Once an element is selected, may be some hotkeys should work as well to interact with it.
I've already implemented the first part: I have a class and a helper
var selectClass = 'selectedView';
var selectView = function(element) {
// remove other selections
jQuery('.'+selectClass).removeClass(selectClass);
// select
jQuery(element).addClass(selectClass);
//# to do: scroll into view
};
and also the click handler:
jQuery(document.body).on('click',viewsSelector,function(ev){
var viewElement = ev.target;
// don't select views' children
while(!jQuery(viewElement).is(viewsSelector) && viewElement.parentElement)
viewElement = viewElement.parentElement;
selectView(viewElement);
});
Now I'd like to implement the keyboard navigation. The naive implementation
jQuery(document.body).on('keydown','.'+selectClass,function(ev){
console.log('keydown at selected? key: '+ev.which+', target is ',ev.target);
//# implement jump
});
doesn't work, because the target is body
(which can easily be checked by commenting out the delegation bit ,'.'+selectClass
).
But I don't want to handle all keypresses, I need to make those work only when an item is selected. As a workaround I can add a check whether an item is selected, but I wonder if there's a way to make the event's target be the item itself, not document.body
. Adding element.focus();
and jQuery(element).focus();
to selectView
doesn't help neither.
One particular reason why I'd like to avoid just handling keypresses on body
and checking if an item is selected is that some widgets inside items also have to handle those keypresses and "jumps" are not expected in those cases.
Your element is not receiving keyboard events because it is not focused when clicked. All elements are not able to recieve focus when clicked as they don't have tabindex focus flag set except for the following elements. [source:www.w3.org]
<a>
elements that have an href attribute<link>
elements that have an href attribute<button>
elements<input>
elements whose type attribute are not in the Hidden state<select>
elements<textarea>
elements- Editing hosts
- Browsing context containers
If an element is not in focus keyboard events are recieved by the body
element.
When an element is focused, key events received by the document must be targeted at that element. There may be no element focused; when no element is focused, key events received by the document must be targeted at the body element. [source:www.w3.org]
You can make any HTML element able to receive focus and thereby receive keyboard events by adding a tabindex
property.
$('.box').on('keydown', function(event) {
console.log(event.target);
})
.box {
height: 120px;
width: 120px;
background: #7cf76e;
float: left;
margin: 2px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="box" tabindex="1">A</div>
<div class="box" tabindex="1">B</div>
<div class="box" tabindex="1">C</div>