2

As a follow up to Select range in contenteditable div

Stackoverflow doesn't allow me comment to Tim's "answer", but I've just tried the Tims code into jsfiddle and I don't see it working on Chrome or Edge now, maybe it worked on an earlier browser

var mainDiv = document.getElementById("main");
var startNode = mainDiv.firstChild.firstChild;
var endNode = mainDiv.childNodes[2].firstChild;

var range = document.createRange();
range.setStart(startNode, 6); // 6 is the offset of "world" within "Hello world"
range.setEnd(endNode, 7); // 7 is the length of "this is"
var sel = window.getSelection();
sel.removeAllRanges();
sel.addRange(range);

https://jsfiddle.net/Abeeee/zc7kwar8/1/

Edge throws the console error "Invalid argument" pointing at the range.setStart command (line 6), and the Chrome console says "Uncaught TypeError: Failed to execute 'setStart' on 'Range': parameter 1 is not of type 'Node'" on the same range.setStart line.

Does anyone have an suggestion on how to make this work on a "modern" browser? (Chrome Version 62.0.3202.94 (Official Build) (64-bit))

Thanks Abe

cнŝdk
  • 31,391
  • 7
  • 56
  • 78
user1432181
  • 918
  • 1
  • 9
  • 24
  • `console.log(startNode, endNode);` right after you declare and define them, both are `null`. The firstChild of mainDiv is not the element, but the textNode created from white space between the tags. – skyline3000 Nov 29 '17 at 20:43

2 Answers2

2

In fact startNode and endNode are undefined, because by mainDiv.firstChild and mainDiv.childNodes[2] you were pointing to 2 text nodes, which don't have child elements, that's why you will get undefined by calling firstChild upon them.

In fact these text nodes are created by the fact you make a new line between all your tags, so you need to point to the right elements.

This is how should your startNode and endNode be defined:

var mainDiv = document.getElementById("main");
var startNode = mainDiv.childNodes[1].firstChild;
var endNode = mainDiv.childNodes[5].firstChild;

Demo:

var mainDiv = document.getElementById("main");
var startNode = mainDiv.childNodes[1].firstChild;
var endNode = mainDiv.childNodes[5].firstChild;
console.dir(mainDiv.childNodes);
console.log(endNode);
var range = document.createRange();
range.setStart(startNode, 6); // 6 is the offset of "world" within "Hello world"
range.setEnd(endNode, 7); // 7 is the length of "this is"
var sel = window.getSelection();
sel.removeAllRanges();
sel.addRange(range);
<div id="main" contenteditable="true" style="border:solid 1px black; width:300px; height:300px">
  <div id='one'>Hello world!</div>
  <div id='two'>
    <br>
  </div>
  <div id='three'>This is a paragraph</div>
</div>
cнŝdk
  • 31,391
  • 7
  • 56
  • 78
1

Remember that white space between tags in HTML creates textNodes between your elements, and these count as children when using childNodes. Your startNode and endNode variables are actually null because mainDiv.firstChild is referring to a textNode and textNodes do not have children. Your variables should instead be:

var startNode = mainDiv.childNodes[1].firstChild;
var endNode = mainDiv.childNodes[5].firstChild;

See the updated JSFiddle: https://jsfiddle.net/zc7kwar8/3/

skyline3000
  • 7,639
  • 2
  • 24
  • 33
  • Indeed. Using console logs you could have easily debug what was happening. Heres and update fiddles as well with the logs: https://jsfiddle.net/zc7kwar8/4/ – Ph0b0x Nov 29 '17 at 20:59