html native dropdown - open menu items on enter click - javascript

on select enter click, by default form gets submitted on.As per accessibility criteria, if focus is on select element on enter click it should open list items. I want to know is it possible to make accessible dropdown using native select element which will meet accessibility criteria
<div class="custom-dropdown">
<select id="cities" name="select">
<option value="1">Delhi</option>
<option value="2">Mumbai</option>
</select>``
</div>
I have prevented default submission behaviour.
$('.custom-dropdown').keydown(function (event) {
if (event.keyCode == 13) {
event.preventDefault();
return false;
}
});
I have tried keyup event to trigger click event but its not working
$('#cities').keyup(function (e) {
if (e.keyCode == 13) {
$("#cities").trigger("click");
}
});

I'm pretty sure the only element that will submit a form automatically is a submit button.
<input type="submit" value="foo">
or
<button>foo</button>
(the default type for a <button> element is "submit")
The <select> is not defined as submitting a form. Are you sure your focus is on the <select> when you press enter?
You should also look at the specs for "4.10.18.6. Form submission"

You're basing your concern on an example, not the specification:
The example listbox on this page implements the following keyboard interface
If you refer to Keyboard Interaction for the Listbox Design Pattern, the Enter key is not mentioned.
The example uses Enter, because the trigger for the listbox is a Button.
Also, in general, ARIA rules are meant for cases where you cannot use standard elements, according to the First rule of ARIA use
If you can use a native HTML element [HTML51] or attribute with the semantics and behavior you require already built in, instead of re-purposing an element and adding an ARIA role, state or property to make it accessible, then do so.
In other words, you shouldn't care about those rules, when you don't implement your own controls.

Related

Should the HTML <select> element dispatch `beforeinput` events?

The MDN page for beforeinput states that:
The DOM beforeinput event fires when the value of an <input>, <select>, or <textarea> element is about to be modified
<select> is clearly mentioned as supporting the beforeinput event.
This also seems to be true based on my simple reading of the spec:
Trusted Targets: Element (specifically: control types such as HTMLInputElement, etc.) or any Element with contenteditable attribute enabled
(emphasis mine)
However, no browser seems to implement it. I have checked Chrome, Safari and Firefox.
Am I understanding something incorrectly?
const sel = document.getElementById('pet-select')
sel.addEventListener('beforeinput', () => console.log('beforeinput!'))
sel.addEventListener('input', () => console.log('input!'))
<label for="pet-select">Choose a pet:</label>
<select name="pets" id="pet-select">
<option value="">--Please choose an option--</option>
<option value="dog">Dog</option>
<option value="cat">Cat</option>
<option value="hamster">Hamster</option>
<option value="parrot">Parrot</option>
<option value="spider">Spider</option>
<option value="goldfish">Goldfish</option>
</select>
The MDN page copied its summary from the input event page, which does indeed fire on this element. I did open a PR there to rectify this.
The beforeinput event isn't supposed to fire on <select>, just like it doesn't fire on non textual inputs:
addEventListener('input', () => console.log('input!'))
addEventListener('beforeinput', () => console.log('beforeinput!'))
<input type=text placeholder="here it fires"><br>
<input type=checkbox><br>
<input type=radio><br>
<input type=file><br>
<input type=color>
To understand that, we need to go back in History and see how the input event was first designed by the HTML's specs.
It's only after some times that it got moved to the W3C/UI-Events working group.
The beforeinput one on the other hand was drafted by the W3C/Editing group and then transferred to the W3C/UI-Events.
The discussions in the W3C/UI-Events group make it clear that their intent was for it to fire only for changes that came from user keyboard inputs. They even initially expected it to NOT fire for actions such as paste or cut.
Ok, but why does the input event fires on <select> and other non textual input elements?
That's because the HTML specs (now handled by WHATWG) actually still do define the input event and ask for it to happen:
For the <select> element they say:
When the user agent is to send select update notifications, queue an element task on the user interaction task source given the select element to run these steps:
Fire an event named input at the select element, with the bubbles and composed attributes initialized to true.
As for textual <input> they say:
When the input and change events apply (which is the case for all input controls other than buttons and those with the type attribute in the Hidden state), the events are fired to indicate that the user has interacted with the control. The input event fires whenever the user has modified the data of the control.
And for checkboxes:, radio, and file inputs you'll find something along these lines:
The input activation behavior is to run the following steps:
If the element is not connected, then return.
Fire an event named input at the element with the bubbles and composed attributes initialized to true.
Fire an event named change at the element with the bubbles attribute initialized to true.
The only mention to the beforeinput event in the HTML specs has been added only 11 days ago, but that PR only exposes the event globally, it doesn't change its definition.

onchange() event of dropdownlist missing after disabled

I have an ASP.NET MVC project at work. Browser: Internet Explorer (forget what version), but my work machine is 32bit Windows 7.
In one of the view page, I have a dropdownlist. If there is any change, it will populate a text box with certain value. Here is the code (translated to HTML): Please note the drop down list is in a form
<form>
<select id="searchType" name="searchType" onchange="FillMyTextBox()">
<option value="1" selected>A</option>
<option value="2">B</option>
...
</select>
</form>
At the top of page, I have a button called 'Commit'. Once this button is clicked, all fields are disabled and form is submitted. $('input, select').attr('disabled', 'true') The 'Commit' button will be gone, and another button 'Back' appears. This 'Back' button, if clicked, will set all fields editable and form is submitted. $('input, select').removeAttr('disabled') (I guess you are aware of, these two sections of code use jQuery.)
However, once the 'Commit' button is pressed, select has attribute disabled and form is submitted. Once the form / page comes back, I find out the onchange() function is missing in the dropdownlist. Why? I use document.getElementById('searchType).hasAttribute('onchange') and it returns false (when I am in Console tab of Internet Explorer developer tool).
Why the disabled attribute remove the onchange() event of a dropdownlist? Is this a design flaw? I mean if I have many controls on the page, if I disable these controls, but somehow later on enable them back (say user review what has entered, but find out need to re-enter some fields), then I have to re-associate each with its own event, it seems rather inefficient.
[Edit] Stress that drop down list is inside a form and each button will cause the form to be submitted [/Edit]
Try using $('input, select').prop('disabled', false) to see if it works.
Or in other way this page may help. According to the answer assigning attribute uses $("input").attr('disabled','disabled') and removing by $("input").removeAttr('disabled');

Event Control with KeyPress 'Tab'

So I have several input forms that are disabled until they are filled out in sequence because of data calls to the server based on their selections. I have a custom dropdown that allows me to do a typeahead and click the item I want. When I click the item, the field unlocks with a combination of onblur and onchange events that take place for my data model. The issue that comes into play for me is I want the user to be able to tab. But when I hit tab, the onblur and onchange haven't disabled the field so it skips several fields that it shouldn't. Is there any suggestions on preventing a tab keypress skipping the disabled element? Can I tab and focus on a disabled element?
That is not possible, as the docs say:
A form control is disabled if its disabled attribute is set, or if it is a descendant of a fieldset element whose disabled attribute is set and is not a descendant of that fieldset element's first legend element child, if any.
A form control that is disabled must prevent any click events that are queued on the user interaction task source from being dispatched on the element.
So you can not click on those elements, and you can not focus element, that can not be clicked.
https://www.w3.org/TR/html5/forms.html#concept-fe-disabled
So the only option if you need to allow focusing of those elements is not to use disabled attribute at all. You could use .disabled class instead and bind on key events to suppress editing of the value.
Assuming you are willing to temporarily enable the disabled element (thus making it writable), this can be done by checking whether the next element has the disabled attribute with hasAttribute(). If it does, you can change this attribute to false before the keydown returns true, and thus the keyup will tab to the disabled element.
Additionally, you can set a new attribute wasDisabled, which you can then check against with $(this)[0]. If the element has this class, you can re-disable the element once you tab off it again.
This can be seen in the following jQuery example:
$('input').on('keydown', function(e) {
if (e.keyCode == 9) {
if ($(this).next()[0].hasAttribute('disabled')) {
$(this).next().attr('disabled', false);
$(this).next().attr('wasdisabled', true);
}
if ($(this)[0].hasAttribute('wasdisabled')) {
$(this).attr('disabled', true);
}
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input>
<input disabled>
<input>
Hope this helps! :)
I ended up switching it to a readonly property. The readonly allowed me to tab to it and focus on it while not being able to type in it until the the blur and change completed.

Enter triggers button click

I have a page with two buttons. One is a <button> element and the other is a <input type="submit">. The buttons appear on the page in that order. If I'm in a text field anywhere in the form and press <Enter>, the button element's click event is triggered. I assume that's because the button element sits first.
I can't find anything that looks like a reliable way of setting the default button, nor do I necessarily want to at this point. In the absence of anything better, I've captured a keypress anywhere on the form and, if it was the <Enter> key that was pressed, I'm just negating it:
$('form').keypress( function( e ) {
var code = e.keyCode || e.which;
if( code === 13 ) {
e.preventDefault();
return false;
}
})
As far as I can tell so far, it seems to be working, but it feels incredibly ham-fisted.
Does anyone know of a more sophisticated technique for doing this?
Similarly, are there any pitfalls to this solution that I'm just not aware of?
Thanks.
Using
<button type="button">Whatever</button>
should do the trick.
The reason is because a button inside a form has its type implicitly set to submit. As zzzzBoz says, the Spec says that the first button or input with type="submit" is what is triggered in this situation. If you specifically set type="button", then it's removed from consideration by the browser.
It is important to read the HTML specifications to truly understand what behavior is to be expected:
The HTML5 spec explicitly states what happens in implicit submissions:
A form element's default button is the first submit button in tree order whose form owner is that form element.
If the user agent supports letting the user submit a form implicitly (for example, on some platforms hitting the "enter" key while a text field is focused implicitly submits the form), then doing so for a form whose default button has a defined activation behavior must cause the user agent to run synthetic click activation steps on that default button.
This was not made explicit in the HTML4 spec, however browsers have already been implementing what is described in the HTML5 spec (which is why it's included explicitly).
Edit to add:
The simplest answer I can think of is to put your submit button as the first [type="submit"] item in the form, add padding to the bottom of the form with css, and absolutely position the submit button at the bottom where you'd like it.
Where ever you use a <button> element by default it considers that button type="submit" so if you define the button type="button" then it won't consider that <button> as submit button.
I don't think you need javascript or CSS to fix this.
According to the html 5 spec for buttons a button with no type attribute is treated the same as a button with its type set to "submit", i.e. as a button for submitting its containing form. Setting the button's type to "button" should prevent the behaviour you're seeing.
I'm not sure about browser support for this, but the same behaviour was specified in the html 4.01 spec for buttons so I expect it's pretty good.
By pressing 'Enter' on focused <input type="text"> you trigger 'click' event on the first positioned element: <button> or <input type="submit">. If you press 'Enter' in <textarea>, you just make a new text line.
See the example here.
Your code prevents to make a new text line in <textarea>, so you have to catch key press only for <input type="text">.
But why do you need to press Enter in text field? If you want to submit form by pressing 'Enter', but the <button> must stay the first in the layout, just play with the markup: put the <input type="submit"> code before the <button> and use CSS to save the layout you need.
Catching 'Enter' and saving markup:
$('input[type="text"]').keypress(function (e) {
var code = e.keyCode || e.which;
if (code === 13) {
e.preventDefault();
// also submit by pressing Enter:
$("form").submit();
}
});
Pressing enter in a form's text field will, by default, submit the form. If you don't want it to work that way you have to capture the enter key press and consume it like you've done. There is no way around this. It will work this way even if there is no button present in the form.
You can use javascript to block form submission until the appropriate time. A very crude example:
<form onsubmit='return false;' id='frmNoEnterSubmit' action="index.html">
<input type='text' name='txtTest' />
<input type='button' value='Submit'
onclick='document.forms["frmNoEnterSubmit"].onsubmit=""; document.forms["frmNoEnterSubmit"].submit();' />
</form>
Pressing enter will still trigger the form to submit, but the javascript will keep it from actually submitting, until you actually press the button.
Dom example
<button onclick="anotherFoo()"> Add new row</button>
<input type="text" name="xxx" onclick="foo(event)">
javascript
function foo(event){
if(event.which == 13 || event.keyCode == 13) // for crossbrowser
{
event.preventDefault(); // this code prevents other buttons triggers use this
// do stuff
}
}
function anotherFoo(){
// stuffs.
}
if you don't use preventDefault(), other buttons will triggered.
I would do it like the following: In the handler for the onclick event of the button (not submit) check the event object's keycode. If it is "enter" I would return false.
My situation has two Submit buttons within the form element: Update and Delete. The Delete button deletes an image and the Update button updates the database with the text fields in the form.
Because the Delete button was first in the form, it was the default button on Enter key. Not what I wanted. The user would expect to be able to hit Enter after changing some text fields.
I found my answer to setting the default button here:
<form action="/action_page.php" method="get" id="form1">
First name: <input type="text" name="fname"><br>
Last name: <input type="text" name="lname"><br>
</form>
<button type="submit" form="form1" value="Submit">Submit</button>
Without using any script, I defined the form that each button belongs to using the <button> form="bla" attribute. I set the Delete button to a form that doesn't exist and set the Update button I wanted to trigger on the Enter key to the form that the user would be in when entering text.
This is the only thing that has worked for me so far.
You can do something like this.
bind your event into a common function and call the event either with keypress or button click.
for example.
function callME(event){
alert('Hi');
}
$('button').on("click",callME);
$('input ').keypress(function(event){
if (event.which == 13) {
callME(event);
}
});
I added a button of type "submit" as first element of the form and made it invisible (width:0;height:0;padding:0;margin:0;border-style:none;font-size:0;). Works like a refresh of the site, i.e. I don't do anything when the button is pressed except that the site is loaded again. For me works fine...

Selectively enable enter key in HTML textarea (javascript)

I am using openjs.com's shortcut handling (1)
to disable the enter key in my html forms. However, inside of textareas in those forms I want enter key to emit the normal CR-LF pair (because that's what users expect).
At the moment assuming I have a form/input structure as follows:
<form id="f1">
<fieldset>
<input>
<textarea id="f2"> ...
The following scripts are run:
shortcut.add('Return', function () { /*empty*/ },
{ 'type':'keydown', 'disable_in_input':false,'propagate':true,
'target':document.getElementById('f1')});"
This effectively disables the enter key.
I have tried using the following code to re-enable it for the textarea:
shortcut.add(\"Enter\", function() { }, {'type':'keydown','propagate':false,
'disable_in_input':false, 'target':document.getElementById('f2') } );
But that does not work. What is the order of propagation of this event? Should it bubble up from the textarea or bubble down from the form element?
It doesn't look like this library was really meant to be used this way. I would hazard a guess that adding any shortcut disables the browser's handling of it entirely, no matter what you do afterwards.
What are you actually trying to accomplish? If you just want to prevent the form from being submitted, you could add a submit event listener for the whole form that calls event.preventDefault().

Categories