Issue encountered while attempting to utilize setStart and setEnd functions on Range object: Unhandled IndexSizeError: Unable to execute 'setEnd' on 'Range'

Every time I attempt to utilize a range, an error message appears in the console:

Uncaught IndexSizeError: Failed to execute 'setEnd' on 'Range': The offset 2 is larger than or equal to the node's length (0).

This is the script I am using:

<script type="text/javascript">
    function gotMark() {
        var range = document.createRange();
        var startNode = document.getElementById("dividTeste1").firstChild;

        range.setStart(startNode, 0);
        range.setEnd(startNode, 2);

        var newNode = document.createElement("span");
        range.surroundContents(newNode);
    }
</script>

And here is a snippet of the page:

<div class="ui-block-a" id="divid" value="div1">
    <div style="background-color: black; color: white; padding: 20px;" id="divid2">
        <h2>London</h2>
        <p id="dividTeste1">London is the capital city of England. It is the most
            populous city in the United Kingdom, with a metropolitan area of
            over 13 million inhabitants.</p>
    </div>
        
    <div style="background-color: black; color: white; padding: 20px;" id="divid2">
        <h2>London</h2>
        <p id="dividTeste2">London is the capital city of England. It is the most
            populous city in the United Kingdom, with a metropolitan area of
            over 13 million inhabitants.</p>
    </div>
</div>
<input type="button" value="Marcar com range" onClick="gotMark()"
        id="marcarconranger12" />

I made an effort to adhere to the guidance provided in dom range.setStart / setEnd for selecting the start and end positions.

Answer №1

I managed to resolve the issue with just one simple line of code:

function highlightText() {
    var selection = document.createRange();
    var startingPoint = document.getElementById("targetElement").firstChild;

    selection.setStart(startingPoint, 0);
    selection.setEnd(startingPoint, 2);

    var newHighlight = document.createElement("span");
    newHighlight.className = 'highlight-yellow'; // <-- this is the line that did the trick

    selection.surroundContents(newHighlight);
}

The text has now been highlighted as intended.

Answer №2

While the code provided by OP appears to be secure and within limits, complications often arise when multiple alterations are made to the same node. This can alter its properties and disrupt any subsequent calculations of offsets that have been made.

For instance, imagine we want to apply highlighting to a paragraph based on an array of start-end pairs. The straightforward approach involves iterating through the pairs in sequence and applying the necessary modifications for each start-end range:

const addHighlights = (textElement, positions) =>
  positions.forEach(([start, end]) => {
    const selectionRange = document.createRange();
    selectionRange.setStart(textElement.firstChild, start);
    selectionRange.setEnd(textElement.firstChild, end);
    const highlightSpan = document.createElement("span");
    highlightSpan.style.background = "#0f6";
    selectionRange.surroundContents(highlightSpan);
  })
;

const positions = [[0, 3], [8, 11]];
addHighlights(document.querySelector("p"), positions);
<p>foo bar baz</p>

To resolve this issue, it is important to ensure that the positions are properly sorted and do not overlap. Furthermore, it is advisable to iterate in reverse order so that changes in the content of the node do not impact earlier index offsets within the content.

const addHighlights = (textElement, positions) =>
  positions.slice().reverse().forEach(([start, end]) => {
    const selectionRange = document.createRange();
    selectionRange.setStart(textElement.firstChild, start);
    selectionRange.setEnd(textElement.firstChild, end);
    const highlightSpan = document.createElement("span");
    highlightSpan.style.background = "#0f6";
    selectionRange.surroundContents(highlightSpan);
  })
;

const positions = [[0, 3], [8, 11]];
addHighlights(document.querySelector("p"), positions);
<p>foo bar baz</p>

Situations where offset computations span multiple nodes can also lead to problems. It is crucial to ensure that the offset is local to the node specified as the first argument in the range.

There are various strategies available to avoid such issues, such as using Node.normalize() to combine text children, constructing the desired text on a new node or string before setting .innerHTML once it is ready, and more.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

`The header navigation is not responding to window resizing functionality`

I am currently developing a header navigation that consists of a logo on the left side, a profile icon on the right side, and some navigation links in the middle. A left slide menu has been implemented to trigger when the window width is less than 700px. ...

Tips for showing images with the full path URL retrieved from JSON using AngularJS

I am currently working on a project that involves displaying images from a JSON file. The URLs of these images are stored in the JSON file. Currently, my code is only outputting the URLs themselves, which is expected. However, I am looking for a way to act ...

Hmm, seems like there's an issue with the touchable child - it must either be native or forward setNativeProps to

Currently enrolled in a ReactNative course on Coursera, I am facing an error in a 4-year-old course: "Touchable child must either be native or forward setNativeProps to a native component." I am unsure about this error and would greatly appreciate any hel ...

Exploring Elasticsearch: Uncovering search results in any scenario

I've been working on a project where my objective is to receive search engine results under all conditions. Even if I enter a keyword that is not included in the search data or if it is an empty string, I still want to get some kind of result. How can ...

Issue with Express.js res.append function: Headers cannot be set after they have already been sent

I encountered an issue in my express project where I tried to set multiple cookies using "res.append" in the same request, but I kept getting an error saying "Error: Can't set headers after they are sent.". Can someone help me identify the problem and ...

Having an issue with HTML and JavaScript where the button won't open when pressed. Any help is appreciated

https://jsbin.com/haluhifuqe/edit?html,js,output I'm facing an issue with my HTML & JavaScript code - when I click the button, it doesn't open. Can anyone help me out? <!DOCTYPE html> <html> <head> <meta charset="utf-8 ...

In Internet Explorer 11, the input event in VueJS may not be triggered upon the first input

I am working with an input HTML element that has @input="onInput" assigned to it. Within the onInput method, I have console log output set up, specifically I am logging event.currentTarget.value. However, I've noticed a strange behavior in IE11 - whe ...

Incorporate a 1-second delay for each value in the stream using Bacon.js

Here is my code snippet: var bulk = array[1,2,3,4] var finalResult = Bacon .fromArray(bulk) .flatMap(isValInCouchDb) .filter(onesThatExist) .flatMap(putValInCouchDb) I want to introduce a 1-second delay after the filter operation before e ...

Tips for designing the microphone appearance on the Google Chrome speech input interface

Google Chrome features an input control for speech recognition. If you want to know how to use it, check out this link. I'm looking to enlarge the microphone icon and possibly use a customized image for it. Increasing the width and height of the inp ...

Utilize the JSSOR Slider to dynamically pull images from an online album, such as by integrating with an RSS Feed

My main motivation for exploring this possibility is the negative impact that loading images into the slider has on my website's performance. Is there a method to import images from an externally hosted album, such as Google Picasa albums (or any othe ...

Building secure applications with React and Express using private routes

In my experience, I have primarily utilized server-side rendering solutions to transfer data from the server to the client and display it in the browser. One of the key advantages of this approach is the ability to access data and send it to the client wi ...

Tips for breaking apart elements of a JavaScript array when a specific delimiter is present in an object property

I am facing a challenge with an array of objects where some properties contain commas. My goal is to split these properties into new objects and recursively copy the rest of the properties into new array elements. For example, consider this original array ...

Turn off automatic calling of Javascript function via the menu

Can anyone help me with calling a JS function from an action link? Here's my declaration: <li><a href="javascript:myFunc()"><span class="glyphicon glyphicon-ok"></span>&nbsp;Test</a></li> The issue is that the ...

Tips for maintaining circular references when converting a JavaScript object to JSON string format

Currently, I am developing a filetree-like object that has a unique structure: var myObject = { 'name':'foo', 'contains': {'thisObject': myObject,'parentObject': /* the object that contains the cur ...

What is the best way to incorporate multiple functions within a React button?

I need to implement a functionality where the startClick function is triggered on BackButton click before executing the dispatch (giveForm2PreviousStep(props.currentStep, props.goToStep)) method. How can this be achieved? Inquiry JS const Inquiry = props ...

What is the best way to create a loop within a JavaScript function?

I'm having some trouble with looping inside a function. It seems like my looping is not working properly and I need help fixing it, along with suggestions for the problem. :) Here's what I've tried: <script> function getImage1( ...

Embed the AJAX response into HTML format

I am facing a challenge with rendering an AJAX response in an HTML structure within a PHP file. The issue is that the AJAX response contains multiple data objects, and each of them needs to be placed in specific locations within the HTML. For example, let ...

When restarting the React application, CSS styles disappear from the page

While developing my React application, I encountered a problem with the CSS styling of the Select component from Material UI. Specifically, when I attempt to remove padding from the Select component, the padding is successfully removed. However, upon refre ...

External vendor scripts such as JavaScript and jQuery are not functioning properly after being rendered in a ReactJS environment

I am currently developing a frontend web app using ReactJS. I obtained a template from W3layout that is built with HTML5, CSS3, and custom JS files, along with various third-party/vendor plugins like nice-select, bootstrap, slik, owl-carousel, etc. Despit ...

eliminating list item from unordered list depending on the input of either first or last name

My objective is to refine a lengthy list as the user types in a search for a specific person by first or last name. The current code I have functions adequately, but encounters an issue when there is a space in the input field. My goal is to allow users to ...