[javascript] Inserting a text where cursor is using Javascript/jquery

I have a page with a lot of textboxes. When someone clicks a link, i want a word or two to be inserted where the cursor is, or appended to the textbox which has the focus.

For example, if the cursor/focus is on a textbox saying 'apple' and he clicks a link saying '[email]', then i want the textbox to say, 'apple [email protected]'.

How can I do this? Is this even possible, since what if the focus is on a radio/dropdown/non textbox element? Can the last focused on textbox be remembered?

This question is related to javascript jquery

The answer is


Use this, from here:

_x000D_
_x000D_
function insertAtCaret(areaId, text) {_x000D_
  var txtarea = document.getElementById(areaId);_x000D_
  if (!txtarea) {_x000D_
    return;_x000D_
  }_x000D_
_x000D_
  var scrollPos = txtarea.scrollTop;_x000D_
  var strPos = 0;_x000D_
  var br = ((txtarea.selectionStart || txtarea.selectionStart == '0') ?_x000D_
    "ff" : (document.selection ? "ie" : false));_x000D_
  if (br == "ie") {_x000D_
    txtarea.focus();_x000D_
    var range = document.selection.createRange();_x000D_
    range.moveStart('character', -txtarea.value.length);_x000D_
    strPos = range.text.length;_x000D_
  } else if (br == "ff") {_x000D_
    strPos = txtarea.selectionStart;_x000D_
  }_x000D_
_x000D_
  var front = (txtarea.value).substring(0, strPos);_x000D_
  var back = (txtarea.value).substring(strPos, txtarea.value.length);_x000D_
  txtarea.value = front + text + back;_x000D_
  strPos = strPos + text.length;_x000D_
  if (br == "ie") {_x000D_
    txtarea.focus();_x000D_
    var ieRange = document.selection.createRange();_x000D_
    ieRange.moveStart('character', -txtarea.value.length);_x000D_
    ieRange.moveStart('character', strPos);_x000D_
    ieRange.moveEnd('character', 0);_x000D_
    ieRange.select();_x000D_
  } else if (br == "ff") {_x000D_
    txtarea.selectionStart = strPos;_x000D_
    txtarea.selectionEnd = strPos;_x000D_
    txtarea.focus();_x000D_
  }_x000D_
_x000D_
  txtarea.scrollTop = scrollPos;_x000D_
}
_x000D_
<textarea id="textareaid"></textarea>_x000D_
<a href="#" onclick="insertAtCaret('textareaid', 'text to insert');return false;">Click Here to Insert</a>
_x000D_
_x000D_
_x000D_


The approved answer from George Claghorn worked great for simply inserting text at the cursor position. If the user had selected text though, and you want that text to be replaced (the default experience with most text), you need to make a small change when setting the 'back' variable.

Also, if you don't need to support older versions of IE, modern versions support textarea.selectionStart, so you can take out all of the browser detection, and IE-specific code.

Here is a simplified version that works for Chrome and IE11 at least, and handles replacing selected text.

function insertAtCaret(areaId, text) {
    var txtarea = document.getElementById(areaId);
    var scrollPos = txtarea.scrollTop;
    var caretPos = txtarea.selectionStart;

    var front = (txtarea.value).substring(0, caretPos);
    var back = (txtarea.value).substring(txtarea.selectionEnd, txtarea.value.length);
    txtarea.value = front + text + back;
    caretPos = caretPos + text.length;
    txtarea.selectionStart = caretPos;
    txtarea.selectionEnd = caretPos;
    txtarea.focus();
    txtarea.scrollTop = scrollPos;
}

This jQuery plugin gives you a pre-made way of selection/caret manipulation.


you can only focus required textbox an insert the text there. there is no way to find out where focus is AFAIK (maybe interating over all DOM nodes?).

check this stackoverflow - it has a solution for you: How do I find out which DOM element has the focus?


Adding text to current cursor position involves two steps:

  1. Adding the text at the current cursor position
  2. Updating the current cursor position

Demo: https://codepen.io/anon/pen/qZXmgN

Tested in Chrome 48, Firefox 45, IE 11 and Edge 25

JS:

function addTextAtCaret(textAreaId, text) {
    var textArea = document.getElementById(textAreaId);
    var cursorPosition = textArea.selectionStart;
    addTextAtCursorPosition(textArea, cursorPosition, text);
    updateCursorPosition(cursorPosition, text, textArea);
}
function addTextAtCursorPosition(textArea, cursorPosition, text) {
    var front = (textArea.value).substring(0, cursorPosition);
    var back = (textArea.value).substring(cursorPosition, textArea.value.length);
    textArea.value = front + text + back;
}
function updateCursorPosition(cursorPosition, text, textArea) {
    cursorPosition = cursorPosition + text.length;
    textArea.selectionStart = cursorPosition;
    textArea.selectionEnd = cursorPosition;
    textArea.focus();    
}

HTML:

<div>
    <button type="button" onclick="addTextAtCaret('textArea','Apple')">Insert Apple!</button>
    <button type="button" onclick="addTextAtCaret('textArea','Mango')">Insert Mango!</button>
    <button type="button" onclick="addTextAtCaret('textArea','Orange')">Insert Orange!</button>
</div>
<textarea id="textArea" rows="20" cols="50"></textarea>

Maybe a shorter version, would be easier to understand?

_x000D_
_x000D_
    jQuery("#btn").on('click', function() {_x000D_
        var $txt = jQuery("#txt");_x000D_
        var caretPos = $txt[0].selectionStart;_x000D_
        var textAreaTxt = $txt.val();_x000D_
        var txtToAdd = "stuff";_x000D_
        $txt.val(textAreaTxt.substring(0, caretPos) + txtToAdd + textAreaTxt.substring(caretPos) );_x000D_
    });
_x000D_
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>_x000D_
_x000D_
<textarea id="txt" rows="15" cols="70">There is some text here.</textarea>_x000D_
<input type="button" id="btn" value="OK" />
_x000D_
_x000D_
_x000D_

I wrote this in response to How to add a text to a textbox from the current position of the pointer with jquery?


How to insert some Text to current cursor position of a TextBox through JQuery and JavaScript

Process

  1. Find the Current Cursor Position
  2. Get the Text to be Copied
  3. Set the Text Over there
  4. Update the Cursor position

Here I have 2 TextBoxes and a Button. I have to Click on a certain position on a textbox and then click on the button to paste the text from the other textbox to the the position of the previous textbox.

Main issue here is that getting the current cursor position where we will paste the text.

//Textbox on which to be pasted
<input type="text" id="txtOnWhichToBePasted" />

//Textbox from where to be pasted
<input type="text" id="txtFromWhichToBePasted" />


//Button on which click the text to be pasted
<input type="button" id="btnInsert" value="Insert"/>


<script type="text/javascript">

$(document).ready(function () {
    $('#btnInsert').bind('click', function () {
            var TextToBePasted = $('#txtFromWhichToBePasted').value;
            var ControlOnWhichToBePasted = $('#txtOnWhichToBePasted');

            //Paste the Text
            PasteTag(ControlOnWhichToBePasted, TextToBePasted);
        });
    });

//Function Pasting The Text
function PasteTag(ControlOnWhichToBePasted,TextToBePasted) {
    //Get the position where to be paste

    var CaretPos = 0;
    // IE Support
    if (document.selection) {

        ControlOnWhichToBePasted.focus();
        var Sel = document.selection.createRange();

        Sel.moveStart('character', -ctrl.value.length);

        CaretPos = Sel.text.length;
    }
    // Firefox support
    else if (ControlOnWhichToBePasted.selectionStart || ControlOnWhichToBePasted.selectionStart == '0')
        CaretPos = ControlOnWhichToBePasted.selectionStart;

    //paste the text
    var WholeString = ControlOnWhichToBePasted.value;
    var txt1 = WholeString.substring(0, CaretPos);
    var txt2 = WholeString.substring(CaretPos, WholeString.length);
    WholeString = txt1 + TextToBePasted + txt2;
    var CaretPos = txt1.length + TextToBePasted.length;
    ControlOnWhichToBePasted.value = WholeString;

    //update The cursor position 
    setCaretPosition(ControlOnWhichToBePasted, CaretPos);
}

function setCaretPosition(ControlOnWhichToBePasted, pos) {

    if (ControlOnWhichToBePasted.setSelectionRange) {
        ControlOnWhichToBePasted.focus();
        ControlOnWhichToBePasted.setSelectionRange(pos, pos);
    }
    else if (ControlOnWhichToBePasted.createTextRange) {
        var range = ControlOnWhichToBePasted.createTextRange();
        range.collapse(true);
        range.moveEnd('character', pos);
        range.moveStart('character', pos);
        range.select();
    }
}

</script>

The code above didn't work for me in IE. Here's some code based on this answer.

I took out the getElementById so I could reference the element in a different way.

_x000D_
_x000D_
function insertAtCaret(element, text) {_x000D_
  if (document.selection) {_x000D_
    element.focus();_x000D_
    var sel = document.selection.createRange();_x000D_
    sel.text = text;_x000D_
    element.focus();_x000D_
  } else if (element.selectionStart || element.selectionStart === 0) {_x000D_
    var startPos = element.selectionStart;_x000D_
    var endPos = element.selectionEnd;_x000D_
    var scrollTop = element.scrollTop;_x000D_
    element.value = element.value.substring(0, startPos) +_x000D_
      text + element.value.substring(endPos, element.value.length);_x000D_
    element.focus();_x000D_
    element.selectionStart = startPos + text.length;_x000D_
    element.selectionEnd = startPos + text.length;_x000D_
    element.scrollTop = scrollTop;_x000D_
  } else {_x000D_
    element.value += text;_x000D_
    element.focus();_x000D_
  }_x000D_
}
_x000D_
input{width:100px}_x000D_
label{display:block;margin:10px 0}
_x000D_
<label for="in2copy">Copy text from: <input id="in2copy" type="text" value="x"></label>_x000D_
<label for="in2ins">Element to insert: <input id="in2ins" type="text" value="1,2,3" autofocus></label>_x000D_
<button onclick="insertAtCaret(document.getElementById('in2ins'),document.getElementById('in2copy').value)">Insert</button>
_x000D_
_x000D_
_x000D_

EDIT: Added a running snippet, jQuery is not being used.


This question's answer was posted so long ago and I stumbled upon it via a Google search. HTML5 provides the HTMLInputElement API that includes the setRangeText() method, which replaces a range of text in an <input> or <textarea> element with a new string:

element.setRangeText('abc');

The above would replace the selection made inside element with abc. You can also specify which part of the input value to replace:

element.setRangeText('abc', 3, 5);

The above would replace the 4th till 6th characters of the input value with abc. You can also specify how the selection should be set after the text has been replaced by providing one of the following strings as the 4th parameter:

  • 'preserve' attempts to preserve the selection. This is the default.
  • 'select' selects the newly inserted text.
  • 'start' moves the selection to just before the inserted text.
  • 'end' moves the selection to just after the inserted text.

Browser compatibility

The MDN page for setRangeText doesn't provide browser compatibility data, but I guess it'd be the same as HTMLInputElement.setSelectionRange(), which is basically all modern browsers, IE 9 and above, Edge 12 and above.


The accepted answer didn't work for me on Internet Explorer 9. I checked it and the browser detection was not working properly, it detected ff (firefox) when i was at Internet Explorer.

I just did this change:

if ($.browser.msie) 

Instead of:

if (br == "ie") { 

The resulting code is this one:

function insertAtCaret(areaId,text) {
    var txtarea = document.getElementById(areaId);
    var scrollPos = txtarea.scrollTop;
    var strPos = 0;
    var br = ((txtarea.selectionStart || txtarea.selectionStart == '0') ? 
        "ff" : (document.selection ? "ie" : false ) );

    if ($.browser.msie) { 
        txtarea.focus();
        var range = document.selection.createRange();
        range.moveStart ('character', -txtarea.value.length);
        strPos = range.text.length;
    }
    else if (br == "ff") strPos = txtarea.selectionStart;

    var front = (txtarea.value).substring(0,strPos);  
    var back = (txtarea.value).substring(strPos,txtarea.value.length); 
    txtarea.value=front+text+back;
    strPos = strPos + text.length;
    if (br == "ie") { 
        txtarea.focus();
        var range = document.selection.createRange();
        range.moveStart ('character', -txtarea.value.length);
        range.moveStart ('character', strPos);
        range.moveEnd ('character', 0);
        range.select();
    }
    else if (br == "ff") {
        txtarea.selectionStart = strPos;
        txtarea.selectionEnd = strPos;
        txtarea.focus();
    }
    txtarea.scrollTop = scrollPos;
}

Content Editable, HTML or any other DOM element Selections

If you are trying to insert at caret on a <div contenteditable="true">, this becomes much more difficult, especially if there are children within the editable container.

I have had really great luck using the Rangy library:

It has a ton of great features such as:

  • Save Position or Selection
  • Then later, Restore the Position or Selection
  • Get selection HTML or Plaintext
  • Among many others

The online demo was not working last I checked, however the repo has working demos. To get started, simple download the Repo from Git or NPM, then open ./rangy/demos/index.html

It makes working with caret pos and text selection a breeze!


using @quick_sliv answer:

function insertAtCaret(el, text) {
    var caretPos = el.selectionStart;
    var textAreaTxt = el.value;
    el.value = textAreaTxt.substring(0, caretPos) + text + textAreaTxt.substring(caretPos);
};

I think you could use the following JavaScript to track the last-focused textbox:

<script>
var holdFocus;

function updateFocus(x)
{
    holdFocus = x;
}

function appendTextToLastFocus(text)
{
    holdFocus.value += text;
}
</script>

Usage:

<input type="textbox" onfocus="updateFocus(this)" />
<a href="#" onclick="appendTextToLastFocus('textToAppend')" />

A previous solution (props to gclaghorn) uses textarea and calculates the position of the cursor too, so it may be better for what you want. On the other hand, this one would be more lightweight, if that's what you're looking for.