[javascript] JS. How to replace html element with another element/text, represented in string?

I have a problem with replacing html elements.

For example, here is a table:

<table>
    <tr>
        <td id="idTABLE">0</td>
        <td>END</td>
    </tr>
</table>

(it can be div, span, anything)

And string in JavaScript:

var str = '<td>1</td><td>2</td>';

(It can be anything, 123 text, <span>123 element</span> 456 or <tr><td>123</td> or anything)

How can I replace element idTABLE with str?

So:

<table>
    <tr>
        <td id="idTABLE">0</td>
        <td>END</td>
    </tr>
</table>

Becomes:

<table>
    <tr>
        <td>1</td>
        <td>2</td>
        <td>END</td>
    </tr>
</table> 
<!-- str = '<td>1</td><td>2</td>'; -->

<table>
    <tr>
        123 text
        <td>END</td>
    </tr>
</table>
<!-- str = '123 text' -->

<table>
    <tr> 
        <td>123</td> 
        <td>END</td>
    </tr>
</table>
<!-- str = '<td>123</td>' -->

I tried createElement, replaceChild, cloneNode, but with no result at all =(

This question is related to javascript html replace

The answer is


If you need to actually replace the td you are selecting from the DOM, then you need to first go to the parentNode, then replace the contents replace the innerHTML with a new html string representing what you want. The trick is converting the first-table-cell to a string so you can then use it in a string replace method.

I added a fiddle example: http://jsfiddle.net/vzUF4/

<table><tr><td id="first-table-cell">0</td><td>END</td></tr></table>

<script>
  var firstTableCell = document.getElementById('first-table-cell');
  var tableRow = firstTableCell.parentNode;
  // Create a separate node used to convert node into string.
  var renderingNode = document.createElement('tr');
  renderingNode.appendChild(firstTableCell.cloneNode(true));
  // Do a simple string replace on the html
  var stringVersionOfFirstTableCell = renderingNode.innerHTML;
  tableRow.innerHTML = tableRow.innerHTML.replace(stringVersionOfFirstTableCell,
    '<td>0</td><td>1</td>');
</script>

A lot of the complexity here is that you are mixing DOM methods with string methods. If DOM methods work for your application, it would be much bette to use those. You can also do this with pure DOM methods (document.createElement, removeChild, appendChild), but it takes more lines of code and your question explicitly said you wanted to use a string.


Your input in this case is too ambiguous. Your code will have to know if it should just insert the text as-is or parse out some HTML tags (or otherwise wind up with bad HTML). This is unneeded complexity that you can avoid by adjusting the input you provide.

If the garbled input is unavoidable, then without some sophisticated parsing (preferably in a separate function), you could end up with some bad HTML (like you do in your second example... which is Bad, right?).

I'm guessing you want a function to insert columns into a 1-row table. In this case, your contents should be passed in as an array (without table, tr, td tags). Each array element will be one column.

HTML

<table id="__TABLE__"><tr><td></td></tr></table>

JS

using jQuery for brevity...

function insert_columns (columns)
{
    var $row = $('<tr></tr>');

    for (var i = 0; i < columns.length; i++)
        $row.append('<td>'+columns[i]+'</td>');

    $('#__TABLE__').empty(); // remove everything inside

    $('#__TABLE__').append($row);
}

So then...

insert_columns(['hello', 'there', 'world']);

Result

<table id="__TABLE__"><tr><td>hello</td><td>there</td><td>world</td></tr></table>

use the attribute "innerHTML"

somehow select the table:

var a = document.getElementById('table, div, whatever node, id')
a.innerHTML = your_text

You would first remove the table, then add the new replacement to the table's parent object.

Look up removeChild and appendChild

http://javascript.about.com/library/bldom09.htm

https://developer.mozilla.org/en-US/docs/DOM/Node.appendChild

Edit: jQuery .append allows sting-html without removing tags: http://api.jquery.com/append/


idTABLE.parentElement.innerHTML =  '<span>123 element</span> 456';

while this works, it's still recommended to use getElementById: Do DOM tree elements with ids become global variables?

replaceChild would work fine if you want to go to the trouble of building up your replacement, element by element, using document.createElement and appendChild, but I don't see the point.


Using jQuery you can do this:

var str = '<td>1</td><td>2</td>';
$('#__TABLE__').replaceWith(str);

http://jsfiddle.net/hZBeW/4/

Or in pure javascript:

var str = '<td>1</td><td>2</td>';
var tdElement = document.getElementById('__TABLE__');
var trElement = tdElement.parentNode;
trElement.removeChild(tdElement);
trElement.innerHTML = str + trElement.innerHTML;

http://jsfiddle.net/hZBeW/1/


Because you are talking about your replacement being anything, and also replacing in the middle of an element's children, it becomes more tricky than just inserting a singular element, or directly removing and appending:

function replaceTargetWith( targetID, html ){
  /// find our target
  var i, tmp, elm, last, target = document.getElementById(targetID);
  /// create a temporary div or tr (to support tds)
  tmp = document.createElement(html.indexOf('<td')!=-1?'tr':'div'));
  /// fill that div with our html, this generates our children
  tmp.innerHTML = html;
  /// step through the temporary div's children and insertBefore our target
  i = tmp.childNodes.length;
  /// the insertBefore method was more complicated than I first thought so I 
  /// have improved it. Have to be careful when dealing with child lists as  
  /// they are counted as live lists and so will update as and when you make
  /// changes. This is why it is best to work backwards when moving children 
  /// around, and why I'm assigning the elements I'm working with to `elm` 
  /// and `last`
  last = target;
  while(i--){
    target.parentNode.insertBefore((elm = tmp.childNodes[i]), last);
    last = elm;
  }
  /// remove the target.
  target.parentNode.removeChild(target);
}

example usage:

replaceTargetWith( 'idTABLE', 'I <b>can</b> be <div>anything</div>' );

demo:

By using the .innerHTML of our temporary div this will generate the TextNodes and Elements we need to insert without any hard work. But rather than insert the temporary div itself -- this would give us mark up that we don't want -- we can just scan and insert it's children.

...either that or look to using jQuery and it's replaceWith method.

jQuery('#idTABLE').replaceWith('<blink>Why this tag??</blink>');


update 2012/11/15

As a response to EL 2002's comment above:

It not always possible. For example, when createElement('div') and set its innerHTML as <td>123</td>, this div becomes <div>123</div> (js throws away inappropriate td tag)

The above problem obviously negates my solution as well - I have updated my code above accordingly (at least for the td issue). However for certain HTML this will occur no matter what you do. All user agents interpret HTML via their own parsing rules, but nearly all of them will attempt to auto-correct bad HTML. The only way to achieve exactly what you are talking about (in some of your examples) is to take the HTML out of the DOM entirely, and manipulate it as a string. This will be the only way to achieve a markup string with the following (jQuery will not get around this issue either):

<table><tr>123 text<td>END</td></tr></table>

If you then take this string an inject it into the DOM, depending on the browser you will get the following:

123 text<table><tr><td>END</td></tr></table>

<table><tr><td>END</td></tr></table>

The only question that remains is why you would want to achieve broken HTML in the first place? :)


Examples related to javascript

need to add a class to an element How to make a variable accessible outside a function? Hide Signs that Meteor.js was Used How to create a showdown.js markdown extension Please help me convert this script to a simple image slider Highlight Anchor Links when user manually scrolls? Summing radio input values How to execute an action before close metro app WinJS javascript, for loop defines a dynamic variable name Getting all files in directory with ajax

Examples related to html

Embed ruby within URL : Middleman Blog Please help me convert this script to a simple image slider Generating a list of pages (not posts) without the index file Why there is this "clear" class before footer? Is it possible to change the content HTML5 alert messages? Getting all files in directory with ajax DevTools failed to load SourceMap: Could not load content for chrome-extension How to set width of mat-table column in angular? How to open a link in new tab using angular? ERROR Error: Uncaught (in promise), Cannot match any routes. URL Segment

Examples related to replace

How do I find and replace all occurrences (in all files) in Visual Studio Code? How to find and replace with regex in excel How to replace text in a column of a Pandas dataframe? How to replace negative numbers in Pandas Data Frame by zero Replacing few values in a pandas dataframe column with another value How to replace multiple patterns at once with sed? Using tr to replace newline with space replace special characters in a string python Replace None with NaN in pandas dataframe Batch script to find and replace a string in text file within a minute for files up to 12 MB