How can I get the caret position from within an input field?
I have found a few bits and pieces via Google, but nothing bullet proof.
Basically something like a jQuery plugin would be ideal, so I could simply do
$("#myinput").caretPosition()
Easier update:
Use field.selectionStart example in this answer.
Thanks to #commonSenseCode for pointing this out.
Old answer:
Found this solution. Not jquery based but there is no problem to integrate it to jquery:
/*
** Returns the caret (cursor) position of the specified text field (oField).
** Return value range is 0-oField.value.length.
*/
function doGetCaretPosition (oField) {
// Initialize
var iCaretPos = 0;
// IE Support
if (document.selection) {
// Set focus on the element
oField.focus();
// To get cursor position, get empty selection range
var oSel = document.selection.createRange();
// Move selection start to 0 position
oSel.moveStart('character', -oField.value.length);
// The caret position is selection length
iCaretPos = oSel.text.length;
}
// Firefox support
else if (oField.selectionStart || oField.selectionStart == '0')
iCaretPos = oField.selectionDirection=='backward' ? oField.selectionStart : oField.selectionEnd;
// Return results
return iCaretPos;
}
Use selectionStart. It is compatible with all major browsers.
document.getElementById('foobar').addEventListener('keyup', e => {
console.log('Caret at: ', e.target.selectionStart)
})
<input id="foobar" />
This works only when no type is defined or type="text" or type="textarea" on the input.
I've wrapped the functionality in bezmax's answer into jQuery if anyone wants to use it.
(function($) {
$.fn.getCursorPosition = function() {
var input = this.get(0);
if (!input) return; // No (input) element found
if ('selectionStart' in input) {
// Standard-compliant browsers
return input.selectionStart;
} else if (document.selection) {
// IE
input.focus();
var sel = document.selection.createRange();
var selLen = document.selection.createRange().text.length;
sel.moveStart('character', -input.value.length);
return sel.text.length - selLen;
}
}
})(jQuery);
Got a very simple solution.
Try the following code with verified result-
<html>
<head>
<script>
function f1(el) {
var val = el.value;
alert(val.slice(0, el.selectionStart).length);
}
</script>
</head>
<body>
<input type=text id=t1 value=abcd>
<button onclick="f1(document.getElementById('t1'))">check position</button>
</body>
</html>
I'm giving you the fiddle_demo
There is now a nice plugin for this: The Caret Plugin
Then you can get the position using $("#myTextBox").caret() or set it via $("#myTextBox").caret(position)
(function($) {
$.fn.getCursorPosition = function() {
var input = this.get(0);
if (!input) return; // No (input) element found
if (document.selection) {
// IE
input.focus();
}
return 'selectionStart' in input ? input.selectionStart:'' || Math.abs(document.selection.createRange().moveStart('character', -input.value.length));
}
})(jQuery);
There are a few good answers posted here, but I think you can simplify your code and skip the check for inputElement.selectionStart support: it is not supported only on IE8 and earlier (see documentation) which represents less than 1% of the current browser usage.
var input = document.getElementById('myinput'); // or $('#myinput')[0]
var caretPos = input.selectionStart;
// and if you want to know if there is a selection or not inside your input:
if (input.selectionStart != input.selectionEnd)
{
var selectionValue =
input.value.substring(input.selectionStart, input.selectionEnd);
}
Perhaps you need a selected range in addition to cursor position. Here is a simple function, you don't even need jQuery:
function caretPosition(input) {
var start = input[0].selectionStart,
end = input[0].selectionEnd,
diff = end - start;
if (start >= 0 && start == end) {
// do cursor position actions, example:
console.log('Cursor Position: ' + start);
} else if (start >= 0) {
// do ranged select actions, example:
console.log('Cursor Position: ' + start + ' to ' + end + ' (' + diff + ' selected chars)');
}
}
Let's say you wanna call it on an input whenever it changes or mouse moves cursor position (in this case we are using jQuery .on()). For performance reasons, it may be a good idea to add setTimeout() or something like Underscores _debounce() if events are pouring in:
$('input[type="text"]').on('keyup mouseup mouseleave', function() {
caretPosition($(this));
});
Here is a fiddle if you wanna try it out: https://jsfiddle.net/Dhaupin/91189tq7/
const inpT = document.getElementById("text-box");
const inpC = document.getElementById("text-box-content");
// swch gets inputs .
var swch;
// swch if corsur is active in inputs defaulte is false .
var isSelect = false;
var crnselect;
// on focus
function setSwitch(e) {
swch = e;
isSelect = true;
console.log("set Switch: " + isSelect);
}
// on click ev
function setEmoji() {
if (isSelect) {
console.log("emoji added :)");
swch.value += ":)";
swch.setSelectionRange(2,2 );
isSelect = true;
}
}
// on not selected on input .
function onout() {
// الافنت اون كي اب
crnselect = inpC.selectionStart;
// return input select not active after 200 ms .
var len = swch.value.length;
setTimeout(() => {
(len == swch.value.length)? isSelect = false:isSelect = true;
}, 200);
}
<h1> Try it !</h1>
<input type="text" onfocus = "setSwitch(this)" onfocusout = "onout()" id="text-box" size="20" value="title">
<input type="text" onfocus = "setSwitch(this)" onfocusout = "onout()" id="text-box-content" size="20" value="content">
<button onclick="setEmoji()">emogi :) </button>
The solution is .selectionStart:
var input = document.getElementById('yourINPUTid');
input.selectionEnd = input.selectionStart = yourDESIREDposition;
input.focus();
If .selectionEnd is not assiged, some text (S-->E) will be selected.
.focus() is required when the focus is lost; when you trigger your code (onClick).
I only tested this in Chrome.
If you want more complicated solutions, you have to read the other answers.
Related
I'm trying to implement some maxlength function on SCEditor, which doesn't take into account original textarea maxlength attribute.
By then I'm using the SelectionchangedEvent handler, to get value and substring it if necessary, and replacing it with val() from SCEditor API.
That works so far but the val() function will set value and place caret at the beginning, so if user continues writing it will write at top then substring the bottom, and set back caret on top, one line above previous one.
I don't want that !
So I came across solutions like : stackoverflow
That doesn't seem to work unfornatunately : jsfiddle
var instance = $('textarea').sceditor({
plugins: 'bbcode',
width: '100%',
style: 'http://www.sceditor.com/minified/jquery.sceditor.default.min.css'
}).sceditor('instance');
$('#caretend').click(function() {
placeCaretAtEnd(instance);
});
function placeCaretAtEnd(el) {
el.focus();
if (typeof window.getSelection != "undefined"
&& typeof document.createRange != "undefined") {
var range = document.createRange();
range.selectNodeContents(el.getBody().get(0));
range.collapse(false);
var sel = window.getSelection();
sel.removeAllRanges();
sel.addRange(range);
} else if (typeof document.body.createTextRange != "undefined") {
var textRange = document.body.createTextRange();
textRange.moveToElementText(el.getBody().get(0));
textRange.collapse(false);
textRange.select();
}
}
<link href="http://www.sceditor.com/minified/jquery.sceditor.default.min.css" rel="stylesheet"/>
<div>Place caret at end</div>
<div><textarea></textarea></div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://www.sceditor.com/minified/jquery.sceditor.bbcode.min.js"></script>
Am i missing something right here ? Or is it just this plugin in conflict with the function ?
And finally, I also found some interesting post here : stackoverflow but I don't see how to use in it in the intended way.
Any advice very welcome, thanks a lot in advance.
Well, finally found how to, hoping this could help someone in the future !
Here is my solution, on how to limit input length on SCEditor
Create a flag array that will be used to detect changes on contenteditable, I found that more effective and cross browser compatible that common handlers.
var sceFlag = { "id1" : 0, "id2" : 0 (...) };
Function to placeCaretAtEnd :
function placeCaretAtEnd(instance){
var rangeHelper = instance.getRangeHelper();
var range = rangeHelper.cloneSelected();
if ('selectNodeContents' in range) {
var bodyChildren = instance.getBody()[0].children;
range.selectNodeContents(bodyChildren[bodyChildren.length - 1]);
range.collapse(false);
rangeHelper.selectRange(range);
}
Function to substring value if above max length :
function SCElength(instance,len){
var d = len - instance.val().length;
if(d<0){
instance.val(instance.val().substr(0,len));
placeCaretAtEnd(instance);
}
Function to listen to focus and blur events and check if contenteditable has changed :
function SCEFocusBlur(instance,len,id){
instance.getBody()
.focus(function() {
sceFlag[id] = 1;
checkSCEInput(instance,len,id);
$(this).data("initialText", $(this).html());
});
instance.getBody()
.blur(function() {
sceFlag[id] = 0;
if ($(this).data("initialText") !== $(this).html()) {
checkSCEInput(instance,len,id);
}
});
Function to check value recursively while flag is 1
function checkSCEInput(instance,len,id){
if(sceFlag[id] = 1){
SCElength(instance,len);
setTimeout(function() {
checkSCEInput(instance,len);
}, 1000);
}
Then all you have to do is create the sceditor like this :
$("textarea").sceditor({
plugins: "bbcode",
style: "css/sceditor.min.css",
width: "auto",
height: "110",
toolbar:"bold,italic,underline,strike,subscript,superscript|left,center,right,justify|size,color,removeformat|bulletlist,orderedlist,horizontalrule,emoticon",
});
And call SCEFocusBlur with the instance, the maxlength int and the id associated to the flag :
SCEFocusBlur($("textarea").sceditor('instance'),maxlength,id);
Any thoughts on it very welcome !
Have a good day :)
I have a credit card field that I want to handle while the user inputs its credit card number.
Assumptions are that the user can enter digits and alphabetic characters, and a space must be added every four characters.
The input part works fine, but I have problems with backspace. Deleting with the backspace key works if I the cursor is on a digits, but it does not work fine when the cursor is on a space: in this case the user must hold backspace to properly delete some input.
An additional requirement is to let clipboard actions (copy, cut, paste) work properly on that field.
I cannot use any plugin for the solution (like the JQuery Mask Plugin), and I won't use keyCode directly, if possible.
Updated
JS Fiddle: https://jsfiddle.net/ot2t9zr4/10/
Snippet
$('#credit-card').on('keypress change blur', function () {
$(this).val(function (index, value) {
return value.replace(/[^a-z0-9]+/gi, '').replace(/(.{4})/g, '$1 ');
});
});
$('#credit-card').on('copy cut paste', function () {
setTimeout(function () {
$('#credit-card').trigger("change");
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="container">
<form class="" action="" method="post">
<fieldset>
<legend>Payment</legend>
<div class="beautiful-field field-group credit-cart">
<label class="label" for="credit-card">Credit card</label>
<input class="field" id="credit-card" value="" autocomplete="off" type="text" />
</div>
</fieldset>
</form>
</div>
Bind keypress event only and see.
$('#credit-card').on('keypress change', function () {
$(this).val(function (index, value) {
return value.replace(/\W/gi, '').replace(/(.{4})/g, '$1 ');
});
});
Check here.
Steve Davies already pointed it out, but if you only reformat the whole value with replace(), the caret position will always go at the end of the input value which can be annoying if the user edits what he previously entered. It will lead to a bad user experience if the caret position is elsewhere or a selection has been made in order to replace it with a new digit.
That being said, a good way to get rid of that behavior is to create a custom replace function with a for loop that goes through each character, then you will be able to know if the space inserted is before the current caret position and update the position if it's the case.
Pure javascript solution: https://jsfiddle.net/pmrotule/217u7fru/.
EDIT: I added support for the American Express format (15 digits instead of 16).
input_credit_card = function(jQinp)
{
var format_and_pos = function(input, char, backspace)
{
var start = 0;
var end = 0;
var pos = 0;
var value = input.value;
if (char !== false)
{
start = input.selectionStart;
end = input.selectionEnd;
if (backspace && start > 0) // handle backspace onkeydown
{
start--;
if (value[start] == " ")
{ start--; }
}
// To be able to replace the selection if there is one
value = value.substring(0, start) + char + value.substring(end);
pos = start + char.length; // caret position
}
var d = 0; // digit count
var dd = 0; // total
var gi = 0; // group index
var newV = "";
var groups = /^\D*3[47]/.test(value) ? // check for American Express
[4, 6, 5] : [4, 4, 4, 4];
for (var i = 0; i < value.length; i++)
{
if (/\D/.test(value[i]))
{
if (start > i)
{ pos--; }
}
else
{
if (d === groups[gi])
{
newV += " ";
d = 0;
gi++;
if (start >= i)
{ pos++; }
}
newV += value[i];
d++;
dd++;
}
if (d === groups[gi] && groups.length === gi + 1) // max length
{ break; }
}
input.value = newV;
if (char !== false)
{ input.setSelectionRange(pos, pos); }
};
jQinp.keypress(function(e)
{
var code = e.charCode || e.keyCode || e.which;
// Check for tab and arrow keys (needed in Firefox)
if (code !== 9 && (code < 37 || code > 40) &&
// and CTRL+C / CTRL+V
!(e.ctrlKey && (code === 99 || code === 118)))
{
e.preventDefault();
var char = String.fromCharCode(code);
// if the character is non-digit
// -> return false (the character is not inserted)
if (/\D/.test(char))
{ return false; }
format_and_pos(this, char);
}
}).
keydown(function(e) // backspace doesn't fire the keypress event
{
if (e.keyCode === 8 || e.keyCode === 46) // backspace or delete
{
e.preventDefault();
format_and_pos(this, '', this.selectionStart === this.selectionEnd);
}
}).
on('paste', function()
{
// A timeout is needed to get the new value pasted
setTimeout(function()
{ format_and_pos(jQinp[0], ''); }, 50);
}).
blur(function() // reformat onblur just in case (optional)
{
format_and_pos(this, false);
});
};
input_credit_card($('#credit-card'));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="container">
<form class="" action="" method="post">
<fieldset>
<legend>Payment</legend>
<div class="beautiful-field field-group credit-cart">
<label class="label" for="credit-card">Credit card</label>
<input class="field" id="credit-card" value="" autocomplete="off" type="text" />
</div>
</fieldset>
</form>
</div>
Since I cannot just reply to Developer107's comment; If you only want digits (with regex and don't want to specify it on the field. You can do it like this:
$('#credit-card').on('keypress change', function () {
$(this).val(function (index, value) {
return value.replace(/[^0-9]/g, "").replace(/\W/gi, '').replace(/(.{4})/g, '$1 ');
});
});
https://jsfiddle.net/ot2t9zr4/4/
I wanted to share my solution, in case someone is still struggling to achieve the desired affect.
My code is a refined version of #tonybrasunas's answer. It will add spaces every 4 characters, filter out non-numerical characters, fix character position, backspace, and only move the cursor forward if the character is valid, but still allow pushing with valid characters.
// FORMAT CC FIELD
//
$('#credit-card').on('input', function () {
$(this).val(function (index, value) {
// Store cursor position
let cursor = $(this).get(0).selectionStart;
// Filter characters and shorten CC (expanded for later use)
const filterSpace = value.replace(/\s+/g, '');
const filtered = filterSpace.replace(/[^0-9]/g, '');
const cardNum = filtered.substr(0, 16);
// Handle alternate segment length for American Express
const partitions = cardNum.startsWith('34') || cardNum.startsWith('37') ? [4,6,5] : [4,4,4,4];
// Loop through the validated partition, pushing each segment into cardNumUpdated
const cardNumUpdated = [];
let position = 0;
partitions.forEach(expandCard => {
const segment = cardNum.substr(position, expandCard);
if (segment) cardNumUpdated.push(segment);
position += expandCard;
});
// Combine segment array with spaces
const cardNumFormatted = cardNumUpdated.join(' ');
// Handle cursor position if user edits the number later
if (cursor < cardNumFormatted.length - 1) {
// Determine if the new value entered was valid, and set cursor progression
cursor = filterSpace !== filtered ? cursor - 1 : cursor;
setTimeout(() => {
$(this).get(0).setSelectionRange(cursor, cursor, 'none');
});
}
return cardNumFormatted;
})
});
//
// END OF FORMAT CC FIELD
An Answer for 2021: Handling Backspace, Cursor Position, and American Express correctly
To handle Backspace and cursor arrows, we have to store the original cursor position and restore it with a setTimeout() when editing a spot anywhere other than the end of the string.
For American Express, we set up partitions to handle the 4-6-5 spacing format for Amex and the 4-4-4-4 spacing for all other cards. And we loop through them to add spaces.
$('#credit-card').on('keyup', function () {
$(this).val(function (index, value) {
const selectionStart = $(this).get(0).selectionStart;
let trimmedCardNum = value.replace(/\s+/g, '');
if (trimmedCardNum.length > 16) {
trimmedCardNum = trimmedCardNum.substr(0, 16);
}
/* Handle American Express 4-6-5 spacing format */
const partitions = trimmedCardNum.startsWith('34') || trimmedCardNum.startsWith('37')
? [4,6,5]
: [4,4,4,4];
const numbers = [];
let position = 0;
partitions.forEach(partition => {
const part = trimmedCardNum.substr(position, partition);
if (part) numbers.push(part);
position += partition;
});
const formattedCardNum = numbers.join(' ');
/* Handle caret position if user edits the number later */
if (selectionStart < formattedCardNum.length - 1) {
setTimeout(() => {
$(this).get(0).setSelectionRange(selectionStart, selectionStart, 'none');
});
};
return formattedCardNum;
})
});
If you have a routine of your own to detect American Express numbers, use it. This simply examines the first two digits and compares to PAN/IIN standards.
I also posted an answer on how to do this in an Angular application.
I solved this in Vue JS by creating a custom on-change handler. Rather than show it here, I will provide a link to that solution: Javascript: Set cursor position when changing the value of input
Based on my research, it is required to manage the position of the cursor yourself if you wish to fully-support editing with good UX.
pmrotule's vanilla JavaScript solution is great, but mine is drastically simpler, so it could be worthwhile to examine.
function cc_format(value) {
var v = value.replace(/\s+/g, '').replace(/[^0-9]/gi, '')
var matches = v.match(/\d{4,16}/g);
var match = matches && matches[0] || ''
var parts = []
for (i=0, len=match.length; i<len; i+=4) {
parts.push(match.substring(i, i+4))
}
if (parts.length) {
return parts.join(' ')
} else {
return value
}
}
Use
$('#input-cc-number').on('keyup',function() {
var cc_number = cc_format($(this).val());
$('#input-cc-number').val(cc_number);
});
Your issue at its core is that when an input field's value is updated using JavaScript, the cursor/selection position is set to the end of the string.
When user-input is appending to the end, this is fine, but if deleting, or inserting digits in the middle, this becomes quite annoying as you have observed. One way to deal with this would be to save and restore the cursor position within the field before and after each edit.
Crudely done:
$('#credit-card').on('keyup keypress change', function () {
var s = this.selectionStart, e = this.selectionEnd;
var oldleft = $(this).val().substr(0,s).replace(/[^ ]/g, '').length;
$(this).val(function (index, value) {
return value.replace(/\W/gi, '').replace(/(.{4})/g, '$1 ');
});
var newleft = $(this).val().substr(0,s).replace(/[^ ]/g, '').length;
s += newleft - oldleft;
e += newleft - oldleft;
this.setSelectionRange(s, e);
});
This is not a full solution as the s and e positions will need updating if your code inserts/removes characters that result in these locations being moved.
You could also significantly optimise this by not setting val() if no update is required.
$('.credit-card').keyup(function (e) {
if (e.keyCode != 8) {
if ($(this).val().length == 4) {
$(this).val($(this).val() + " ");
} else if ($(this).val().length == 9) {
$(this).val($(this).val() + " ");
} else if ($(this).val().length == 14) {
$(this).val($(this).val() + " ");
}
}
});
This should work fine its just for card with format 4444 5555 2222 1111 and back space works correctly
To me #pmrotule answer was the best answer so far in this post. Good credit card spacing apparently helps conversion rate in shopping carts according to extensive research produced by Stripe.
Additionally however, setting the "type" attribute of the html input field to "tel" is also important, as well as inputmode="numeric" as well as setting the auto complete type cc-number, all also help improve checkout conversion rate. Especially on mobile when the user gets a numeric keyboard instead of qwerty.
Unfortunately this breaks #pmrotule's code. On another SO post I found out about Cleave.js which is a well tested library for this purpose & plays nicely with the tel input type: https://github.com/nosir/cleave.js
Putting it all together:
<input class="field" id="number" type="tel" inputmode="numeric" autocomplete="cc-number" />
with JS:
var cleave = new Cleave('#number', {
creditCard: true,
onCreditCardTypeChanged: function (type) {
console.log('The detected card type is: '+type);
}
});
I have a form with a textarea (id = details).
Is there a way I can insert the HTML code for a line break (<br />) at the cursor position when hitting Enter within this textarea ?
I would only need this to get to work in IE.
<textarea class="input height120 elastic span12" name="details" id="details" onkeyup="countCharLimit(event)" onpaste="countCharLimit(event)"></textarea>
Try this:
$('textarea').keypress(function (e){
if(e.keyCode == 13){
$('textarea').val($('textarea').val()+"<br />");
}
});
You could try and fiddle with it here
EDIT: I realized this is adding a <br /> at the end only, after some more research, I found this solution:
$('textarea').keypress(function (e){
if(e.keyCode == 13){
e.preventDefault();
this.value = this.value.substring(0, this.selectionStart)+"<br />"+"\n";
}
});
Here is a fiddle for this one
Source (mostly): Insert text into textarea with jQuery
EDIT AGAIN: Looks like the OP wanted the text at the end to also be cleared, so I updated my code accordingly (for other's seeing this: check out the first edit of my relevant fiddle for the case you'd want to keep the remaining text).
you will need to find the caret position first as follow:
var caretPos = function() {
var el = $("#details").get(0);
var pos = 0;
if('selectionStart' in el) {
pos = el.selectionStart;
} else if('selection' in document) {
el.focus();
var Sel = document.selection.createRange();
var SelLength = document.selection.createRange().text.length;
Sel.moveStart('character', -el.value.length);
pos = Sel.text.length - SelLength;
}
return pos;
}
taken from :here
then you do:
var textofDetails = $("#details").val();
jQuery("#detail").val(textofDetails.substring(0, caretPos) + "<br/>" + textofDetails.substring(caretPos) );
Major EDIT:
no need for all the above ; your function will be
function replaceNewLine(){
jQuery("#detail").val().replace(/\\n/g, "<br />");
}
source: so - here
Yes, sure. It seems to be so, that you need keydown event processing and, possible, setTimeout 0 hack, look here: Why is setTimeout(fn, 0) sometimes useful?
How can I get the caret position from within an input field?
I have found a few bits and pieces via Google, but nothing bullet proof.
Basically something like a jQuery plugin would be ideal, so I could simply do
$("#myinput").caretPosition()
Easier update:
Use field.selectionStart example in this answer.
Thanks to #commonSenseCode for pointing this out.
Old answer:
Found this solution. Not jquery based but there is no problem to integrate it to jquery:
/*
** Returns the caret (cursor) position of the specified text field (oField).
** Return value range is 0-oField.value.length.
*/
function doGetCaretPosition (oField) {
// Initialize
var iCaretPos = 0;
// IE Support
if (document.selection) {
// Set focus on the element
oField.focus();
// To get cursor position, get empty selection range
var oSel = document.selection.createRange();
// Move selection start to 0 position
oSel.moveStart('character', -oField.value.length);
// The caret position is selection length
iCaretPos = oSel.text.length;
}
// Firefox support
else if (oField.selectionStart || oField.selectionStart == '0')
iCaretPos = oField.selectionDirection=='backward' ? oField.selectionStart : oField.selectionEnd;
// Return results
return iCaretPos;
}
Use selectionStart. It is compatible with all major browsers.
document.getElementById('foobar').addEventListener('keyup', e => {
console.log('Caret at: ', e.target.selectionStart)
})
<input id="foobar" />
This works only when no type is defined or type="text" or type="textarea" on the input.
I've wrapped the functionality in bezmax's answer into jQuery if anyone wants to use it.
(function($) {
$.fn.getCursorPosition = function() {
var input = this.get(0);
if (!input) return; // No (input) element found
if ('selectionStart' in input) {
// Standard-compliant browsers
return input.selectionStart;
} else if (document.selection) {
// IE
input.focus();
var sel = document.selection.createRange();
var selLen = document.selection.createRange().text.length;
sel.moveStart('character', -input.value.length);
return sel.text.length - selLen;
}
}
})(jQuery);
Got a very simple solution.
Try the following code with verified result-
<html>
<head>
<script>
function f1(el) {
var val = el.value;
alert(val.slice(0, el.selectionStart).length);
}
</script>
</head>
<body>
<input type=text id=t1 value=abcd>
<button onclick="f1(document.getElementById('t1'))">check position</button>
</body>
</html>
I'm giving you the fiddle_demo
There is now a nice plugin for this: The Caret Plugin
Then you can get the position using $("#myTextBox").caret() or set it via $("#myTextBox").caret(position)
(function($) {
$.fn.getCursorPosition = function() {
var input = this.get(0);
if (!input) return; // No (input) element found
if (document.selection) {
// IE
input.focus();
}
return 'selectionStart' in input ? input.selectionStart:'' || Math.abs(document.selection.createRange().moveStart('character', -input.value.length));
}
})(jQuery);
There are a few good answers posted here, but I think you can simplify your code and skip the check for inputElement.selectionStart support: it is not supported only on IE8 and earlier (see documentation) which represents less than 1% of the current browser usage.
var input = document.getElementById('myinput'); // or $('#myinput')[0]
var caretPos = input.selectionStart;
// and if you want to know if there is a selection or not inside your input:
if (input.selectionStart != input.selectionEnd)
{
var selectionValue =
input.value.substring(input.selectionStart, input.selectionEnd);
}
Perhaps you need a selected range in addition to cursor position. Here is a simple function, you don't even need jQuery:
function caretPosition(input) {
var start = input[0].selectionStart,
end = input[0].selectionEnd,
diff = end - start;
if (start >= 0 && start == end) {
// do cursor position actions, example:
console.log('Cursor Position: ' + start);
} else if (start >= 0) {
// do ranged select actions, example:
console.log('Cursor Position: ' + start + ' to ' + end + ' (' + diff + ' selected chars)');
}
}
Let's say you wanna call it on an input whenever it changes or mouse moves cursor position (in this case we are using jQuery .on()). For performance reasons, it may be a good idea to add setTimeout() or something like Underscores _debounce() if events are pouring in:
$('input[type="text"]').on('keyup mouseup mouseleave', function() {
caretPosition($(this));
});
Here is a fiddle if you wanna try it out: https://jsfiddle.net/Dhaupin/91189tq7/
const inpT = document.getElementById("text-box");
const inpC = document.getElementById("text-box-content");
// swch gets inputs .
var swch;
// swch if corsur is active in inputs defaulte is false .
var isSelect = false;
var crnselect;
// on focus
function setSwitch(e) {
swch = e;
isSelect = true;
console.log("set Switch: " + isSelect);
}
// on click ev
function setEmoji() {
if (isSelect) {
console.log("emoji added :)");
swch.value += ":)";
swch.setSelectionRange(2,2 );
isSelect = true;
}
}
// on not selected on input .
function onout() {
// الافنت اون كي اب
crnselect = inpC.selectionStart;
// return input select not active after 200 ms .
var len = swch.value.length;
setTimeout(() => {
(len == swch.value.length)? isSelect = false:isSelect = true;
}, 200);
}
<h1> Try it !</h1>
<input type="text" onfocus = "setSwitch(this)" onfocusout = "onout()" id="text-box" size="20" value="title">
<input type="text" onfocus = "setSwitch(this)" onfocusout = "onout()" id="text-box-content" size="20" value="content">
<button onclick="setEmoji()">emogi :) </button>
The solution is .selectionStart:
var input = document.getElementById('yourINPUTid');
input.selectionEnd = input.selectionStart = yourDESIREDposition;
input.focus();
If .selectionEnd is not assiged, some text (S-->E) will be selected.
.focus() is required when the focus is lost; when you trigger your code (onClick).
I only tested this in Chrome.
If you want more complicated solutions, you have to read the other answers.
What is the best way (and I presume simplest way) to place the cursor at the end of the text in a input text element via JavaScript - after focus has been set to the element?
There's a simple way to get it working in most browsers.
this.selectionStart = this.selectionEnd = this.value.length;
However, due to the *quirks of a few browsers, a more inclusive answer looks more like this
setTimeout(function(){ that.selectionStart = that.selectionEnd = 10000; }, 0);
Using jQuery (to set the listener, but it's not necessary otherwise)
$('#el').focus(function(){
var that = this;
setTimeout(function(){ that.selectionStart = that.selectionEnd = 10000; }, 0);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input id='el' type='text' value='put cursor at end'>
Using Vanilla JS (borrowing addEvent function from this answer)
// Basic cross browser addEvent
function addEvent(elem, event, fn){
if(elem.addEventListener){
elem.addEventListener(event, fn, false);
}else{
elem.attachEvent("on" + event,
function(){ return(fn.call(elem, window.event)); });
}}
var element = document.getElementById('el');
addEvent(element,'focus',function(){
var that = this;
setTimeout(function(){ that.selectionStart = that.selectionEnd = 10000; }, 0);
});
<input id='el' type='text' value='put cursor at end'>
Quirks
Chrome has an odd quirk where the focus event fires before the cursor is moved into the field; which screws my simple solution up. Two options to fix this:
You can add a timeout of 0 ms (to defer the operation until the stack is clear)
You can change the event from focus to mouseup. This would be pretty annoying for the user unless you still kept track of focus. I'm not really in love with either of these options.
Also, #vladkras pointed out that some older versions of Opera incorrectly calculate the length when it has spaces. For this you can use a huge number that should be larger than your string.
Try this, it has worked for me:
//input is the input element
input.focus(); //sets focus to element
var val = this.input.value; //store the value of the element
this.input.value = ''; //clear the value of the element
this.input.value = val; //set that value back.
For the cursor to be move to the end, the input has to have focus first, then when the value is changed it will goto the end. If you set .value to the same, it won't change in chrome.
I faced this same issue (after setting focus through RJS/prototype) in IE.
Firefox was already leaving the cursor at the end when there is already a value for the field. IE was forcing the cursor to the beginning of the text.
The solution I arrived at is as follows:
<input id="search" type="text" value="mycurrtext" size="30"
onfocus="this.value = this.value;" name="search"/>
This works in both IE7 and FF3 but doesn't work in modern browsers (see comments) as it is not specified that UA must overwrite the value in this case (edited in accordance with meta policy).
After hacking around with this a bit, I found the best way was to use the setSelectionRange function if the browser supports it; if not, revert to using the method in Mike Berrow's answer (i.e. replace the value with itself).
I'm also setting scrollTop to a high value in case we're in a vertically-scrollable textarea. (Using an arbitrary high value seems more reliable than $(this).height() in Firefox and Chrome.)
I've made it is as a jQuery plugin. (If you're not using jQuery I trust you can still get the gist easily enough.)
I've tested in IE6, IE7, IE8, Firefox 3.5.5, Google Chrome 3.0, Safari 4.0.4, Opera 10.00.
It's available on jquery.com as the PutCursorAtEnd plugin. For your convenience, the code for release 1.0 is as follows:
// jQuery plugin: PutCursorAtEnd 1.0
// http://plugins.jquery.com/project/PutCursorAtEnd
// by teedyay
//
// Puts the cursor at the end of a textbox/ textarea
// codesnippet: 691e18b1-f4f9-41b4-8fe8-bc8ee51b48d4
(function($)
{
jQuery.fn.putCursorAtEnd = function()
{
return this.each(function()
{
$(this).focus()
// If this function exists...
if (this.setSelectionRange)
{
// ... then use it
// (Doesn't work in IE)
// Double the length because Opera is inconsistent about whether a carriage return is one character or two. Sigh.
var len = $(this).val().length * 2;
this.setSelectionRange(len, len);
}
else
{
// ... otherwise replace the contents with itself
// (Doesn't work in Google Chrome)
$(this).val($(this).val());
}
// Scroll to the bottom, in case we're in a tall textarea
// (Necessary for Firefox and Google Chrome)
this.scrollTop = 999999;
});
};
})(jQuery);
<script type="text/javascript">
function SetEnd(txt) {
if (txt.createTextRange) {
//IE
var FieldRange = txt.createTextRange();
FieldRange.moveStart('character', txt.value.length);
FieldRange.collapse();
FieldRange.select();
}
else {
//Firefox and Opera
txt.focus();
var length = txt.value.length;
txt.setSelectionRange(length, length);
}
}
</script>
This function works for me in IE9, Firefox 6.x, and Opera 11.x
It's 2019 and none of the methods above worked for me, but this one did, taken from https://css-tricks.com/snippets/javascript/move-cursor-to-end-of-input/
function moveCursorToEnd(id) {
var el = document.getElementById(id)
el.focus()
if (typeof el.selectionStart == "number") {
el.selectionStart = el.selectionEnd = el.value.length;
} else if (typeof el.createTextRange != "undefined") {
var range = el.createTextRange();
range.collapse(false);
range.select();
}
}
<input id="myinput" type="text" />
Move cursor to end
I've tried the following with quite great success in chrome
$("input.focus").focus(function () {
var val = this.value,
$this = $(this);
$this.val("");
setTimeout(function () {
$this.val(val);
}, 1);
});
Quick rundown:
It takes every input field with the class focus on it, then stores the old value of the input field in a variable, afterwards it applies the empty string to the input field.
Then it waits 1 milisecond and puts in the old value again.
el.setSelectionRange(-1, -1);
https://codesandbox.io/s/peaceful-bash-x2mti
This method updates the HTMLInputElement.selectionStart, selectionEnd,
and selectionDirection properties in one call.
https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/setSelectionRange
In other js methods -1 usually means (to the) last character. This is the case for this one too, but I couldn't find explicit mention of this behavior in the docs.
Simple. When editing or changing values, first put the focus then set value.
$("#catg_name").focus();
$("#catg_name").val(catg_name);
Still the intermediate variable is needed, (see var val=)
else the cursor behaves strange, we need it at the end.
<body onload="document.getElementById('userinput').focus();">
<form>
<input id="userinput" onfocus="var val=this.value; this.value=''; this.value= val;"
class=large type="text" size="10" maxlength="50" value="beans" name="myinput">
</form>
</body>
const end = input.value.length
input.setSelectionRange(end, end)
// 👇 scroll to the bottom if a textarea has long text
input.focus()
Try this one works with Vanilla JavaScript.
<input type="text" id="yourId" onfocus="let value = this.value; this.value = null; this.value=value" name="nameYouWant" class="yourClass" value="yourValue" placeholder="yourPlaceholder...">
In Js
document.getElementById("yourId").focus()
For all browsers for all cases:
function moveCursorToEnd(el) {
window.setTimeout(function () {
if (typeof el.selectionStart == "number") {
el.selectionStart = el.selectionEnd = el.value.length;
} else if (typeof el.createTextRange != "undefined") {
var range = el.createTextRange();
range.collapse(false);
range.select();
}
}, 1);
}
Timeout required if you need to move cursor from onFocus event handler
I like the accepted answer a lot, but it stopped working in Chrome. In Chrome, for the cursor to go to the end, input value needs to change. The solution is as follow:
<input id="search" type="text" value="mycurrtext" size="30"
onfocus="var value = this.value; this.value = null; this.value = value;" name="search"/>
document.querySelector('input').addEventListener('focus', e => {
const { value } = e.target;
e.target.setSelectionRange(value.length, value.length);
});
<input value="my text" />
In jQuery, that's
$(document).ready(function () {
$('input').focus(function () {
$(this).attr('value',$(this).attr('value'));
}
}
I just found that in iOS, setting textarea.textContent property will place the cursor at the end of the text in the textarea element every time. The behavior was a bug in my app, but seems to be something that you could use intentionally.
This problem is interesting. The most confusing thing about it is that no solution I found solved the problem completely.
+++++++ SOLUTION +++++++
You need a JS function, like this:
function moveCursorToEnd(obj) {
if (!(obj.updating)) {
obj.updating = true;
var oldValue = obj.value;
obj.value = '';
setTimeout(function(){ obj.value = oldValue; obj.updating = false; }, 100);
}
}
You need to call this guy in the onfocus and onclick events.
<input type="text" value="Test Field" onfocus="moveCursorToEnd(this)" onclick="moveCursorToEnd(this)">
IT WORKS ON ALL DEVICES AN BROWSERS!!!!
var valsrch = $('#search').val();
$('#search').val('').focus().val(valsrch);
Taking some of the answers .. making a single-line jquery.
$('#search').focus().val($('#search').val());
If the input field just needs a static default value I usually do this with jQuery:
$('#input').focus().val('Default value');
This seems to work in all browsers.
While this may be an old question with lots of answers, I ran across a similar issue and none of the answers were quite what I wanted and/or were poorly explained. The issue with selectionStart and selectionEnd properties is that they don't exist for input type number (while the question was asked for text type, I reckon it might help others who might have other input types that they need to focus). So if you don't know whether the input type the function will focus is a type number or not, you cannot use that solution.
The solution that works cross browser and for all input types is rather simple:
get and store the value of input in a variable
focus the input
set the value of input to the stored value
That way the cursor is at the end of the input element.
So all you'd do is something like this (using jquery, provided the element selector that one wishes to focus is accessible via 'data-focus-element' data attribute of the clicked element and the function executes after clicking on '.foo' element):
$('.foo').click(function() {
element_selector = $(this).attr('data-focus-element');
$focus = $(element_selector);
value = $focus.val();
$focus.focus();
$focus.val(value);
});
Why does this work? Simply, when the .focus() is called, the focus will be added to the beginning of the input element (which is the core problem here), ignoring the fact, that the input element already has a value in it. However, when the value of an input is changed, the cursor is automatically placed at the end of the value inside input element. So if you override the value with the same value that had been previously entered in the input, the value will look untouched, the cursor will, however, move to the end.
Super easy (you may have to focus on the input element)
inputEl = getElementById('inputId');
var temp = inputEl.value;
inputEl.value = '';
inputEl.value = temp;
Set the cursor when click on text area to the end of text...
Variation of this code is...ALSO works! for Firefox, IE, Safari, Chrome..
In server-side code:
txtAddNoteMessage.Attributes.Add("onClick", "sendCursorToEnd('" & txtAddNoteMessage.ClientID & "');")
In Javascript:
function sendCursorToEnd(obj) {
var value = $(obj).val(); //store the value of the element
var message = "";
if (value != "") {
message = value + "\n";
};
$(obj).focus().val(message);
$(obj).unbind();
}
If you set the value first and then set the focus, the cursor will always appear at the end.
$("#search-button").click(function (event) {
event.preventDefault();
$('#textbox').val('this');
$("#textbox").focus();
return false;
});
Here is the fiddle to test
https://jsfiddle.net/5on50caf/1/
I wanted to put cursor at the end of a "div" element where contenteditable = true, and I got a solution with Xeoncross code:
<input type="button" value="Paste HTML" onclick="document.getElementById('test').focus(); pasteHtmlAtCaret('<b>INSERTED</b>'); ">
<div id="test" contenteditable="true">
Here is some nice text
</div>
And this function do magic:
function pasteHtmlAtCaret(html) {
var sel, range;
if (window.getSelection) {
// IE9 and non-IE
sel = window.getSelection();
if (sel.getRangeAt && sel.rangeCount) {
range = sel.getRangeAt(0);
range.deleteContents();
// Range.createContextualFragment() would be useful here but is
// non-standard and not supported in all browsers (IE9, for one)
var el = document.createElement("div");
el.innerHTML = html;
var frag = document.createDocumentFragment(), node, lastNode;
while ( (node = el.firstChild) ) {
lastNode = frag.appendChild(node);
}
range.insertNode(frag);
// Preserve the selection
if (lastNode) {
range = range.cloneRange();
range.setStartAfter(lastNode);
range.collapse(true);
sel.removeAllRanges();
sel.addRange(range);
}
}
} else if (document.selection && document.selection.type != "Control") {
// IE < 9
document.selection.createRange().pasteHTML(html);
}
}
Works fine for most browsers, please check it, this code puts text and put focus at the end of the text in div element (not input element)
https://jsfiddle.net/Xeoncross/4tUDk/
Thanks, Xeoncross
I also faced same problem. Finally this gonna work for me:
jQuery.fn.putCursorAtEnd = = function() {
return this.each(function() {
// Cache references
var $el = $(this),
el = this;
// Only focus if input isn't already
if (!$el.is(":focus")) {
$el.focus();
}
// If this function exists... (IE 9+)
if (el.setSelectionRange) {
// Double the length because Opera is inconsistent about whether a carriage return is one character or two.
var len = $el.val().length * 2;
// Timeout seems to be required for Blink
setTimeout(function() {
el.setSelectionRange(len, len);
}, 1);
} else {
// As a fallback, replace the contents with itself
// Doesn't work in Chrome, but Chrome supports setSelectionRange
$el.val($el.val());
}
// Scroll to the bottom, in case we're in a tall textarea
// (Necessary for Firefox and Chrome)
this.scrollTop = 999999;
});
};
This is how we can call this:
var searchInput = $("#searchInputOrTextarea");
searchInput
.putCursorAtEnd() // should be chainable
.on("focus", function() { // could be on any event
searchInput.putCursorAtEnd()
});
It's works for me in safari, IE, Chrome, Mozilla. On mobile devices I didn't tried this.
Check this solution!
//fn setCurPosition
$.fn.setCurPosition = function(pos) {
this.focus();
this.each(function(index, elem) {
if (elem.setSelectionRange) {
elem.setSelectionRange(pos, pos);
} else if (elem.createTextRange) {
var range = elem.createTextRange();
range.collapse(true);
range.moveEnd('character', pos);
range.moveStart('character', pos);
range.select();
}
});
return this;
};
// USAGE - Set Cursor ends
$('#str1').setCurPosition($('#str1').val().length);
// USAGE - Set Cursor at 7 position
// $('#str2').setCurPosition(7);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<p>Set cursor at any position</p>
<p><input type="text" id="str1" value="my string here" /></p>
<p><input type="text" id="str2" value="my string here" /></p>
I took the best answers from here, and created a function that works well in Chrome.
You will need to wrap the logic in a timeout, because you have to wait for the focus to finish before accessing the selection
To place the cursor at the end, the selection start needs to be placed at the end
In order to scroll to the end of the input field, the scrollLeft needs to match the scrollWidth
/**
* Upon focus, set the cursor to the end of the text input
* #param {HTMLInputElement} inputEl - An HTML <input> element
*/
const setFocusEnd = (inputEl) => {
setTimeout(() => {
const { scrollWidth, value: { length } } = inputEl;
inputEl.setSelectionRange(length, length);
inputEl.scrollLeft = scrollWidth;
}, 0);
};
document
.querySelector('input')
.addEventListener('focus', (e) => setFocusEnd(e.target));
html, body {
width: 100%;
height: 100%;
margin: 0;
}
body {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
input:focus {
background-color: hsla(240, 100%, 95%, 1.0);
}
<input
type="text"
placeholder="Search..."
value="This is some really, really long text">
<input id="input_1">
<input id="input_2" type="hidden">
<script type="text/javascript">
//save input_1 value to input_2
$("#input_2").val($("#input_1").val());
//empty input_1 and add the saved input_2 into input_1
$("#input_1").val("").val($("#input_2").val()).focus();
</script>