Replace specific word in contenteditable

contenteditable events
contenteditable javascript
contenteditable editor
get position of selected text javascript

I have a contenteditable div

<div id="divTest" contenteditable="true">

I need to get the last word from caret position and on certain condition I have to test and remove this specific word only. Below is how am I doing

$('#divTest').on('keyup focus', function (e) {
           if (e.keyCode == 32) {
               var lastWord = getWordPrecedingCaret(this),                                       spanLastWord = $('#lastWord');

           }
       });

function getWordPrecedingCaret(containerEl) {
               var preceding = "",
                                    sel,
                                    range,
                                    precedingRange;
               if (window.getSelection) {
                   sel = window.getSelection();
                   if (sel.rangeCount > 0) {
                       range = sel.getRangeAt(0).cloneRange();
                       range.collapse(true);
                       range.setStart(containerEl, 0);
                       preceding = range.toString();


                   }
               } else if ((sel = document.selection) && sel.type != "Control") {
                   range = sel.createRange();
                   precedingRange = range.duplicate();
                   precedingRange.moveToElementText(containerEl);
                   precedingRange.setEndPoint("EndToStart", range);
                   preceding = precedingRange.text;
               }

               var words = range.toString().trim().split(' '),
                        lastWord = words[words.length - 1];
                  if (lastWord) {

                   var resultValue = 'some'; // this value is coming from some other function
                   if (resultValue == lastWord) {
                     alert('do nothing');
                       // do nothing
                   }
                 else
                   {
                     alert('replace word');
                     // delete That specific word and replace if with resultValue
                   }
                   return lastWord;

               }
           }

Demo: http://codepen.io/anon/pen/ogzpXV

I have tried range.deleteContents(); but that will delete all the content in the div. How can I replace specific word only?

To work with Ranges we need to keep in mind that we are working with Nodes, not only the text that is rendered. The structure you want to manipulate is:

<div id="divTest" contenteditable="true"> <-- Element Node
    "some text" <-- TextNode
</div>

But it also could be:

<div id="divTest" contenteditable="true"> <-- Element Node
    "some text" <-- TextNode
    "more text" <-- TextNode
    "" <-- TextNode
</div>

To solve your problem is simplier to handle only one TextNode, I propose to use the normalize() function to join all of them into a single one.

Then you only need to set the Range to the word's bounds before deleteContents(). Once deleted, you can insert a new TextNode with the substitution using insertNode().

var wordStart = range.toString().lastIndexOf(lastWord);
var wordEnd = wordStart + lastWord.length;

/* containerEl.firstChild refers to the div's TextNode */                   
range.setStart(containerEl.firstChild, wordStart);
range.setEnd(containerEl.firstChild, wordEnd);
range.deleteContents();
range.insertNode(document.createTextNode(resultValue));

For this to work, you need that the text is in a single TextNode. But after ìnsertNode the div will contain multiple text nodes. To fix this simply call normalize() to join all TextNode elements.

containerEl.normalize();

Edit:

As Basj points out, the original solution fails for multiline. That's because when hitting ENTER the structure changes from:

<div id="divTest" contenteditable="true"> <-- Element Node
    "some text" <-- TextNode
</div>

to something like:

<div id="divTest" contenteditable="true"> <-- Element Node
    <div>"some text"</div>
    <div>"more text"</div>
</div>

I've updated this answer, but it's also worth to read Basj's answer at this question: Replace word before cursor, when multiple lines in contenteditable

JSFiddle demo or runnable code snippet:

document.getElementById('divTest').onkeyup = function (e) {
    if (e.keyCode == 32) {
        getWordPrecedingCaret(this);
    }
};

function getWordPrecedingCaret(containerEl) {
    var preceding = "",
        sel,
        range,
        precedingRange;
    if (window.getSelection) {
        sel = window.getSelection();
        if (sel.rangeCount > 0) {
            range = sel.getRangeAt(0).cloneRange();
            range.collapse(true);
            range.setStart(containerEl, 0);
            preceding = range.toString();
        }
    } else if ((sel = document.selection) && sel.type != "Control") {
        range = sel.createRange();
        precedingRange = range.duplicate();
        precedingRange.moveToElementText(containerEl);
        precedingRange.setEndPoint("EndToStart", range);
        preceding = precedingRange.text;
    }

    var words = range.toString().trim().split(' '),
        lastWord = words[words.length - 1];
        
    if (lastWord) {
        var resultValue = 'some'; // this value is coming from some other function
        if (resultValue == lastWord) {
            console.log('do nothing: ' + lastWord);
            // do nothing
        } else {
            console.log('replace word ' + lastWord);
            
            /* Find word start and end */
            var wordStart = range.endContainer.data.lastIndexOf(lastWord);
            var wordEnd = wordStart + lastWord.length;
            console.log("pos: (" + wordStart + ", " + wordEnd + ")");
                           
            range.setStart(range.endContainer, wordStart);
            range.setEnd(range.endContainer, wordEnd);
            range.deleteContents();
            range.insertNode(document.createTextNode(resultValue));
            // delete That specific word and replace if with resultValue

            /* Merge multiple text nodes */            
            containerEl.normalize();
        }
        return lastWord;
    }
}
<div id="divTest" contenteditable="true">Write words here and hit SPACE BAR</div>

contentEditable div replace url links - JavaScript, I have a contentEditable DIV where I would like to replace any user typed URL (​by matching the string with regular expression) with blue color text wrapped  Replace specific word in contenteditable javascript , jquery , range , contenteditable To work with Ranges we need to keep in mind that we are working with Nodes, not only the text that is rendered.

 words = ['oele', 'geel', 'politie', 'foo bar'];

function markWords() {
    var html = div.html().replace(/<\/?strong>/gi, ''),
        text = html.replace(/<[^>]+>/g, ' ').replace(/\s+/g, ' '),
        exp;
    $.each(words, function(i, word) {
        exp = new RegExp('\\b(' + word + ')\\b', 'gi');
        html = html.replace(exp, function(m) {
console.log('WORD MATCH:', m);
            return '<strong>' + m + '</strong>';
        });
    });
    //html = html.replace('&nbsp;', ' ').replace(/\s+/g, ' ');
console.log('HTML:', html);
console.log('----');
    div.html(html);
}

Call this function on setinterval

Fiddle

How to replace selected text with javascript or jquery in content , How to replace selected text with javascript or jquery. or insert text at cursor position. 1delete a specific commit and keep the log2020-02-25 13:08:02. 6. <div id="textareaid" contenteditable="true" style="border:1px solid #CCC">. 4. Debating me breeding be answered an he. Spoil event was words her off cause any. When an HTML element has contenteditable set to true, the document.execCommand() method is made available. This lets you run commands to manipulate the contents of the editable region. Most commands affect the document's selection by, for example, applying a style to the text (bold, italics, etc), while others insert new elements (like adding a link) or affect an entire line (indenting).

Tobías' solution works well for single-line contenteditable div. But if you add multiple lines, it doesn't work anymore.

Here is a general solution that works for both single-line or multiline contenteditable div.

Mark certain words while typing in a [contenteditable], $.each(words, function(i, word) {. 11 html = html.replace(exp, function(m) {. 13 getSelection();//get the selection object (allows you to change selection). 44. Find and replace text Go to Home > Replace or press Ctrl+H. Enter the word or phrase you want to locate in the Find box. Enter your new text in the Replace box. Select Find Next until you come to the word you want to update. Choose Replace. To update all instances at once, choose Replace All.

How can I color specific words on content editable element , to color specific words on a content editable div for example if the user wrote. text.replace(word, "<span style='color:blue;'>" + word + "</span>"); } return text;  To find and replace all occurrences of case insensitive ‘eth1’ with ‘br1’, enter: :%s/eth1/br1/gi The above example will find eth1, ETH1, eTh1, ETh1 and so on and replace with br1. To find and replace all occurrences of ‘eth1’ with ‘br1’ for lines from 3 to 7, enter: :3,7s/eth1/br1/g.

Playing with CSS Contenteditable, You can replace a form element with a contenteditable div and some basic serif; word-wrap: break-word; min-width: 300px; padding: 30px; background-color​:  Definition and Usage. The replace() method searches a string for a specified value, or a regular expression, and returns a new string where the specified values are replaced. Note: If you are replacing a value (and not a regular expression ), only the first instance of the value will be replaced.

contentEditable, "false" - The content is not editable. Technical Details. Return Value: A String, returns true if the element is editable  I've combined Word in Doc mode and HTML mode into one column. Only differences are with tab vs spaces. Recommendation for HTML 5: This is largely context-specific, so recomendations are provided in the far right column of the table below.

Comments
  • I've added some css in order to highlight the editable div (it was transparent). It should work at least in FF and Chrome. Thanks for your feedback.
  • If you add multiple lines and hit SPACE, it doesn't work anymore. See also here.
  • I've edited the answer and added a reference to your solution. Thanks.
  • it is going to replace each word within the contenteditable with the replacement word, right? Let say, I have text like this "Test one Test two Test | Three Test" Now because my cursor is before Three so I want to replace only that Test word.