input event - losing focus while dragging input element - javascript

I'm trying to make a score module using a range input. I'm using the input event to achieve this. The range input works fine, but when I add event, it loses focus shortly after dragging begins.
This is how it looks:
document.querySelector("#score").addEventListener("input", e => {
console.log(e.target.value);
});
<input type="range" min="1" max="10" value="10" draggable="true" class="score theme" id="score" step="0.1">

That happens because you added draggable="true" to the element. So the behaviour is ambiguous, should the browser allow you to move the trackball or should the browser drag the element around the page?
The two behaviours are conflicting, so in the first moment it works properly as an input range and you're able to move it around, but then it allows you to drag the element.
What's your expected behaviour?
document.querySelector("#score").addEventListener("input", e => {
console.log(e.target.value);
});
<input type="range" min="1" max="10" value="10" class="score theme" id="score" step="0.1">

draggable="true" doesn’t do what you think it does. An <input type="range"> has a draggable component to it by default. The draggable attribute makes it so that you can drag the entire element.
Removing this attribute gives the expected behaviour:
document.getElementById('score').addEventListener('input', e => {
console.log(e.target.value);
});
<input type="range" min="1" max="10" value="10" id="score" step="0.1">

This seems to be a problem with the draggable="true" attribute and not the JavaScript code. The draggable attribute allows us to make the element draggable around the DOM, i.e. from one position to another in the viewport.
Therefore, when one tries to drag the range handle, the whole slider gets dragged along, instead of just the handle, which is what you described as "losing focus".
So, the solution is to simply remove the draggable=true attribute. I made a pen on CodePen to demonstrate this. https://codepen.io/aryan_02/pen/WPNBYm
Notice what the draggable attribute does. I hope this helps you.

Related

Shifting jQuery focus to next div separated input

I have 3 inputs for every div container (e.g. first-section, second-section ...), and I have several such div containers on my page, similar to this:
...
<div id="first-section">
<fieldset>
<legend>First Section</legend>
<input type="number" placeholder="000" id="input1" min="0" max="255" autofocus maxlength="3" required>
...
</fieldset>
</div>
<div id="second-section">
<fieldset>
<legend>Second Section</legend>
<input type="number" placeholder="000" id="input2" autofocus min="0" max="255" maxlength="3" required>
...
how can I use jQuery to move from input1 to input2 to input3 (not shown) to input4 (not shown) only after the user has entered the maxlength of input which is set to 3? My jQuery below does not work because when I move onto the third input (not shown), it keeps resetting the focus back to input 2.
$(':input').keyup(function(e){
if($(this).val().length==$(this).attr('maxlength')){
$(this).nextAll(':input').first().focus();
if($('#input1').val().length==$('#input1').attr('maxlength')){
$('#input2').focus();
}
}
})
You can find the div that contains the current input, then find the next sibling of the div and the input inside the next div element and set the focus to that.
$(this).closest('div').next().find(':input').first().focus();
Demo: Fiddle
The above one has following issues:
unable to move to previous tab once its filled.
skips the text box which is already filled.
makes things worst if you have JS validations on any input fields.
Use the below jQuery plug-in its easy to configure and use:
Developer Site: http://www.mathachew.com/sandbox/jquery-autotab/
Documentation: https://github.com/Mathachew/jquery-autotab/blob/master/README.md
Includes both Angular and React examples
Cheers...

How to dynamically update range slider

I've created the following code to show the user their range slider value. However, it only shows the value when the user stops moving the slider. Is there a way to show the value WHILE the user drags the range slider? I'm looking for a way to do this in vanilla JS.
function updateInput(val) {
document.getElementById('textInput').innerHTML=val;
}
<input type="range" name="rangeInput" min="0" max="100" onchange="updateInput(this.value);">
<p id="textInput"></p>
Here you go:
<input type="range" name="rangeInput" min="0" max="100" onchange="updateInput(this.value);" oninput="updateInput(this.value)" >
<p id="textInput"></p>
oninput is not supported in IE10, so you have to use both, oninput and onchange.
Here is the demo
Use oninput instead of onchange.
Magical proof!
onmousemove function make this happen:
<input type="range" name="rangeInput" min="0" max="100" onmousemove="document.getElementById('textInput').innerHTML=this.value;">
<p id="textInput"></p>

How do I create one of those draggable settings bars in html?

I've seen those draggable settings bars for random things, but I can't seem to remember what they were called, and thus am having a hard time to search it up on google.
It was one of those bars where if you dragged to the right, the value increases and if you dragged it to the left, the value decreases.
What's the easiest way to create one of these in html/css/js?
What you are looking for is called a range and is an input element:
<input type="range" min="1" max="10">
To get the out put you could use JavaScript and <output>:
<form oninput="x.value=parseInt(a.value)">
<input type="range" id="a" value="50">
<output name="x" for="a b"></output>
</form>
JSFiddle Example

How to repeat the tabindex from 1 after it has gone to the last element with a tabindex?

So, for example, here's a script:
<!-- Random content above this comment -->
<input type="text" tabindex="1" />
<input type="text" tabindex="2" />
<input type="text" tabindex="3" />
<input type="text" tabindex="4" />
<input type="text" tabindex="5" />
<input type="text" tabindex="6" />
<!-- Nothing underneath this comment -->
So, when the user presses tab and goes through the six textboxes, reaches the last one and then presses tab, it would go to the content above the first comment, right? Well, how do I make it start from tabindex="1" again?
Unfortunately, you can't do that without javascript. You can listen to a TAB (and make sure it's not SHIFT+TAB) key press on your last element and manually set the focus to your first element inside the handler. However, binding this logic to keyboard events (i.e. specific input method) is not universal and may not work when using:
A mobile browser
Some other entertainment device (smart tv, gaming console, etc. - they typically use a D-Pad for jumping between focusable elements)
An accessibility service
I suggest a more universal approach which is agnostic of how the focus is changed.
The idea is that you surround your form elements (where you want to create a "tabindex loop") with special "focus guard" elements that are focusable too (they have a tabindex assigned). Here is your modified HTML:
<p>Some sample content here...</p>
<p>Like, another <input type="text" value="input" /> element or a <button>button</button>...</p>
<!-- Random content above this comment -->
<!-- Special "focus guard" elements around your
if you manually set tabindex for your form elements, you should set tabindex for the focus guards as well -->
<div class="focusguard" id="focusguard-1" tabindex="1"></div>
<input id="firstInput" type="text" tabindex="2" class="autofocus" />
<input type="text" tabindex="3" />
<input type="text" tabindex="4" />
<input type="text" tabindex="5" />
<input type="text" tabindex="6" />
<input id="lastInput" type="text" tabindex="7" />
<!-- focus guard in the end of the form -->
<div class="focusguard" id="focusguard-2" tabindex="8"></div>
<!-- Nothing underneath this comment -->
Now you just listen to focus events on those guard elements and manually change focus to the appropriate field (jQuery used for the sake of simplicity):
$('#focusguard-2').on('focus', function() {
// "last" focus guard got focus: set focus to the first field
$('#firstInput').focus();
});
$('#focusguard-1').on('focus', function() {
// "first" focus guard got focus: set focus to the last field
$('#lastInput').focus();
});
As you see, I also made sure that we snap back to the last input when the focus moves backwards from the first input (e.g. SHIFT+TAB on the first input). Live example
Note that the focus guards are assigned a tabindex value too to make sure they are focused immediately before/after your input fields. If you don't manually set tabindex to your inputs, then both focus guards can just have tabindex="0" assigned.
Of course you can make this all work in a dynamic environment as well, when your form is generated dynamically. Just figure out your focusable elements (less trivial task) and surround them with the same focus guards.
Hope that helps, let me know if you have any issues.
UPDATE
As nbro pointed out, the above implementation has the unwanted effect of selecting the last element if one hits TAB after the page loads (as this would focus the first focusable element which is #focusguard-1, and that would trigger focusing the last input. To mitigate that, you can specify which element you want initially focused and focus it with another little piece of JavaScript:
$(function() { // can replace the onload function with any other even like showing of a dialog
$('.autofocus').focus();
})
With this, just set the autofocus class on whatever element you want, and it'll be focused on page load (or any other event you listen to).
Here my solution where you no need any other elements. As you can see elements will be looping inside <form> elements.
$('form').each(function(){
var list = $(this).find('*[tabindex]').sort(function(a,b){ return a.tabIndex < b.tabIndex ? -1 : 1; }),
first = list.first();
list.last().on('keydown', function(e){
if( e.keyCode === 9 ) {
first.focus();
return false;
}
});
});
Here is my solution, considering the first input has the "autofocus" attribute set:
Add this after your form element (with HTML5 it can be any tag):
<div tabindex="6" onFocus="document.querySelector('[autofocus]').focus()"></div>
Yes, after tabbing through the inputs it will jump on suitable elements that do not have a tab order specified. But also, after tabbing all "tabbable" elements, the focus will jump "outside" your page content, onto the browser's UI elements (tabs, menus, bookmarks, etc)
I think the easiest way is to handle the keyup event on the last input and intercept TAB usage (and SHIFT+TAB for that matter)
I wd suggest you to increase your tabindex ie. >100
and also give the tabIndex to your "content" container div
please note that your content container must have tabindex less than input boxes for ex.99 .
when you press tab on last input box manually set focus on your content div using javascript (you can use keypress handlers for tab key)
document.getElementById("content").focus();
you must giv tabindex to your "content" to set focus to it.
now if you press tab focus will automatically shift to first input box.
hope this will help.
Thank you

range input disable does not work in chrome

I am disabling my range input however in chrome it shows it grayed out but it is still usable.
<input type="range" disabled min="0" max="100"/>
I would assume the above would not allow you to change its value.
Am I doing it wrong?
jsFiddle
Relevant specification Disabled
Here is the Chrome bug report, guess just need to wait for version 15 as the commenters mentioned.
Bug 54820
you can remove all binded events of that specific scroll group to make that scroll disable like:
<div id="fieldset1">
<input type="range" disabled min="0" max="100" readonly="1"/>
</div>
<script>
$(":range").rangeinput();
$('#fieldset1 *').unbind(); // for all events
</script>
its works ..
no need to disable text field; beacause on form submission that field will not be posted ..
My solution JSFIDDLE (Works fine in default android browser)
html
<input id="range" type="range" value="10" min="0" max="30" step="10"/>
<button id="disableBtn">Disable</button>
JS
document.getElementById('disableBtn').addEventListener('input', filter);
document.getElementById('disableBtn').addEventListener('click', disable);
function disable(){
document.getElementById('range').disabled = !document.getElementById('range').disabled;
}
function filter(){
if(document.getElementById('range').disabled){
document.getElementById('range').value = document.getElementById('range').defaultValue;
}
}
I found a corny solution for chrome, because it doesn't seem like you can disable it from user input. Put a div over it so a user cannot interact with it. Not pretty but works:
<div style="position:relative;">
<div style="position:absolute;z-index:5;width:100%;height:100%;"></div>
<input type="range" disbaled=True min="0" max="100" value="0"/><span id="v">100</span>
</div>

Categories