ar099968
ar099968

Reputation: 7537

javascript: move caret to end of element (div with contenteditable)

I have this function for focusing a contenteditable div and move the caret on the end of the text, but it doesn't work as expected.

click on button "Move caret to end", the caret position is 1 instead of div#foo length. But if you click on the "g" character of "i'm a string" the caret position is 12

function moveCaretToEnd(nativeElement) {
        nativeElement.focus();
        if (window.getSelection) {
          if (typeof window.getSelection !== 'undefined' && typeof document.createRange !== 'undefined') {
            const range = document.createRange();
            range.selectNodeContents(nativeElement.firstChild);
            range.collapse(false);
            const sel = window.getSelection();
            sel.removeAllRanges();
            sel.addRange(range);
          }
        }
        updateCaretPos(window.getSelection().anchorOffset);
}

function updateCaretPos(pos){
   document.getElementById('caretpos').innerHTML = pos;
}
<div id="foo" contenteditable="true" onclick="updateCaretPos(window.getSelection().anchorOffset)" style="border: 1px solid grey">i'm a string</div>
<p>Caret position <div id="caretpos"></div></p>
<button onclick="moveCaretToEnd(document.getElementById('foo'))">Move caret to end</button>

Upvotes: 1

Views: 646

Answers (2)

Poul Bak
Poul Bak

Reputation: 10929

You pass 'this' to the function, but 'this' will be the 'button', not the div.

Try this html instead:

<button onclick="moveCaretToEnd(document.getElementById('foo'))">Move caret to end</button>

Edit:

To select the textNode, you can try:

range.selectNodeContents(nativeElement.firstChild);

Upvotes: 1

Nir Tzezana
Nir Tzezana

Reputation: 2342

You are trying to pass the button itself as the element for the caret to appear, I suggest you do as following:

function moveCaretToEnd(nativeElement) {
        // If nothing passed, choose an element by default
        nativeElement = nativeElement || document.getElementById('foo');
        nativeElement.focus();
        if (window.getSelection) {
          if (typeof window.getSelection !== 'undefined' && typeof document.createRange !== 'undefined') {
            const range = document.createRange();
            range.selectNodeContents(nativeElement);
            range.collapse(false);
            const sel = window.getSelection();
            sel.removeAllRanges();
            sel.addRange(range);
          }
        }
        updateCaretPos();
}

function updateCaretPos(){
   document.getElementById('caretpos').innerHTML = window.getSelection().anchorOffset;
}



moveCaretToEnd(document.getElementById('foo'));

And on the HTML side, I added type="button" on the button so it won't submit:

<div id="foo" contenteditable="true" onclick="updateCaretPos()">click me</div>
<p>Caret position <div id="caretpos"></div></p>
<button type="button" onclick="moveCaretToEnd()">Move caret to end</button>

Upvotes: 2

Related Questions