rangy icon indicating copy to clipboard operation
rangy copied to clipboard

Contenteditable: Cannot restore selection after setting innerHTML programmatically

Open rake5k opened this issue 9 years ago • 4 comments

If I try to restore the cursor in a contentEditable div after changing innerHTML, it doesn't work and I get the following warning:

Rangy warning: Module SaveRestore: Marker element has been removed. Cannot restore selection.

My code looks like this:

import rangy from 'rangy';
import 'rangy/lib/rangy-selectionsaverestore';
import React from 'react';
import ReactContentEditable from 'react-contenteditable';

function ContentEditable({ content, isEditable = true, onChange }) {
    return (
        <div>
            <ReactContentEditable
                disabled={!isEditable}
                html={content}
                onChange={handleChange(onChange, maxLength)} />
        </div>
    );
}

function handleChange(onChange) {
    return (event) => {
        const value = event.target.value;

        // some logic here...

        const savedSelection = rangy.saveSelection(event.nativeEvent.target);
        event.nativeEvent.target.innerHTML = doSomethingWithTheValue(value);
        rangy.restoreSelection(savedSelection);
    }
}

After reading http://stackoverflow.com/questions/5595956/replace-innerhtml-in-contenteditable-div I was hopeful to get it running this way.

Any suggestions?

rake5k avatar May 16 '16 14:05 rake5k

@christianharke did you manage to get this working?

KokoChris avatar May 27 '17 15:05 KokoChris

@KokoChris nope, still open issue

rake5k avatar May 27 '17 15:05 rake5k

got the same problem? any chance you fixed it?

ghost avatar Sep 01 '17 21:09 ghost

Sorry for the late response. We worked around the problem without using rangy (we stopped setting innerHtml directly, using react-contenteditable now). For completeness... We reset our cursor position like this now:

/**
 * Sets the cursor position on the provided element
 *
 * @example (if no previous cursor position is known)
 * Cursor is set to the end of the provided element
 *
 * @example (if givenCursorPosition=10)
 * Cursor is set to position 10 in the provided element
 *
 * @param {Element} element - The DOM element on which to set the cursorPosition
 * @param {number} givenCursorPosition - The last known cursor position for this element
 * @returns {undefined}
 */
function setCursorPosition(element, givenCursorPosition = null) {
    const selection = window.getSelection();
    if (selection && element) {
        const cursorPosition = givenCursorPosition
            ? Math.min(givenCursorPosition, element.length)
            : element.length;

        selection.removeAllRanges();
        const range = document.createRange();
        range.setStart(element, cursorPosition);
        selection.addRange(range);
    }
}

rake5k avatar Jan 03 '18 10:01 rake5k