jQuery: how to change tag name?
Asked Answered
C

19

71

jQuery: how to change tag name?

For example:

<tr>
    $1
</tr>

I need

<div>
    $1
</div>

Yes, I can

  1. Create DOM element <div>
  2. Copy tr content to div
  3. Remove tr from dom

But can I make it directly?

PS:

    $(tr).get(0).tagName = "div"; 

results in DOMException.

Caroleecarolin answered 8/8, 2010 at 20:3 Comment(3)
In this special case, it would not make sense to just "rename" it because div won't be a valid element where tr is located.Boxhaul
See this post for a more complete solution that includes all attributes: #2816183Moschatel
you can also use display:block to make a tr act and look like a div without actually changing the tag name but you would probably want to display:blockify the inner tds as well with something like tr,tr>td{display:block}.Chronograph
H
58

You can replace any HTML markup by using jQuery's .replaceWith() method.

example: http://jsfiddle.net/JHmaV/

Ref.: .replaceWith

If you want to keep the existing markup, you could use code like this:

$('#target').replaceWith('<newTag>' + $('#target').html() +'</newTag>')
Harass answered 8/8, 2010 at 20:8 Comment(4)
This will work, but you won't carry over the dom element's properties (styles, events) etc. I don't think there exists a good way to really achieve a full node name change.Aalborg
Sorry, it is NOT a "rename", it destroy all contents (all innerHTML changes!).Chromyl
it is a replace, not rename!Tachograph
Well to keep events etc of the contents, one could have .replaceWith($('<newTag>').append($('#target').contents())Wardle
L
48

No, it is not possible according to W3C specification: "tagName of type DOMString, readonly"

http://www.w3.org/TR/DOM-Level-2-Core/core.html

Latarsha answered 8/8, 2010 at 20:26 Comment(1)
I thing que puchu's question is only about "rename procedure" (!), and there are a "DOM ugly way" to do rename: 1) createElement(new_name) 2) copy all content to new element; 3) replace old to new by replaceChild()Chromyl
S
19

The above solutions wipe out the existing element and re-create it from scratch, destroying any event bindings on children in the process.

short answer: (loses <p/>'s attributes)

$("p").wrapInner("<div/>").children(0).unwrap();

longer answer: (copies <p/>'s attributes)

$("p").each(function (o, elt) {
  var newElt = $("<div class='p'/>");
  Array.prototype.slice.call(elt.attributes).forEach(function(a) {
    newElt.attr(a.name, a.value);
  });
  $(elt).wrapInner(newElt).children(0).unwrap();
});

fiddle with nested bindings

It would be cool to copy any bindings from the at the same time, but getting current bindings didn't work for me.

Spallation answered 5/5, 2015 at 17:24 Comment(0)
C
16

Where the DOM renameNode() Method?

Today (2014) no browser understand the new DOM3 renameNode method (see also W3C) check if run at your bowser: http://jsfiddle.net/k2jSm/1/

So, a DOM solution is ugly and I not understand why (??) jQuery not implemented a workaround?

pure DOM algorithm

  1. createElement(new_name)
  2. copy all content to new element;
  3. replace old to new by replaceChild()

is something like this,

function rename_element(node,name) {
    var renamed = document.createElement(name); 
    foreach (node.attributes as a) {
        renamed.setAttribute(a.nodeName, a.nodeValue);
    }
    while (node.firstChild) {
        renamed.appendChild(node.firstChild);
    }
    return node.parentNode.replaceChild(renamed, node);
}

... wait review and jsfiddle ...

jQuery algorithm

The @ilpoldo algorithm is a good start point,

   $from.replaceWith($('<'+newname+'/>').html($from.html()));

As others commented, it need a attribute copy ... wait generic ...

specific for class, preserving the attribute, see http://jsfiddle.net/cDgpS/

See also https://mcmap.net/q/276327/-jquery-javascript-replace-tag-type

Chromyl answered 8/8, 2010 at 20:3 Comment(0)
G
8

To preserve the internal content of the tag you can use the accessor .html() in conjunction with .replaceWith()

forked example: http://jsfiddle.net/WVb2Q/1/

Goree answered 24/11, 2010 at 20:8 Comment(4)
how about saving all attributes of any element?Trudi
just what i was searching for +1. Attributes are not included with other solutions, until now, this one is a better oneKern
No, it doesn't preserve the attributes.Moschatel
Yes... But it is in the right direction! It is a "rename procedure"... Complement it with a attribute-copy, https://mcmap.net/q/67442/-how-to-copy-all-the-attributes-of-one-element-and-apply-them-to-another, or using clone.Chromyl
C
8

Inspired by ericP answer, formatted and converted to jQuery plugin:

$.fn.replaceWithTag = function(tagName) {
    var result = [];
    this.each(function() {
        var newElem = $('<' + tagName + '>').get(0);
        for (var i = 0; i < this.attributes.length; i++) {
            newElem.setAttribute(
                this.attributes[i].name, this.attributes[i].value
            );
        }
        newElem = $(this).wrapInner(newElem).children(0).unwrap().get(0);
        result.push(newElem);
    });
    return $(result);
};

Usage:

$('div').replaceWithTag('span')
Corinacorine answered 4/10, 2018 at 15:32 Comment(0)
M
6

Working pure DOM algorithm

function rename_element(node, name) {
    let renamed = document.createElement(name);

    Array.from(node.attributes).forEach(attr => {
        renamed.setAttribute(attr.name, attr.value);        
    })
    while (node.firstChild) {
        renamed.appendChild(node.firstChild);
    }
    node.parentNode.replaceChild(renamed, node);
    return renamed;
}

Motherinlaw answered 14/10, 2019 at 8:44 Comment(1)
Pretty modern code, and works. Usage example: $('blockquote').each(function(){let ren = rename_element(this, 'div'); $(ren).doMoreJqueryStuff()})Viridity
A
3

You could go a little basic. Works for me.

var oNode = document.getElementsByTagName('tr')[0];

var inHTML = oNode.innerHTML;
oNode.innerHTML = '';
var outHTML = oNode.outerHTML;
outHTML = outHTML.replace(/tr/g, 'div');
oNode.outerHTML = outHTML;
oNode.innerHTML = inHTML;
Arlenarlena answered 30/1, 2014 at 21:33 Comment(2)
It is not jQuery and is replace string is not a secure or generic strategy, use DOM or jQuery.Chromyl
<div data-divanslation="now you are in divouble">...</div>Viridity
G
2

To replace the internal contents of multiple tags, each with their own original content, you have to use .replaceWith() and .html() differently:

http://jsfiddle.net/kcrca/VYxxG/

Glen answered 21/7, 2011 at 13:39 Comment(2)
It is a copy of @Goree solution, and can be better as commented there. A copy-solution must be deleted.Chromyl
I used this as jquery mobile sometimes generates double selectsFyke
M
2

JS to change the tag name

/**
 * This function replaces the DOM elements's tag name with you desire
 * Example:
 *        replaceElem('header','ram');
 *        replaceElem('div.header-one','ram');
 */
function replaceElem(targetId, replaceWith){
  $(targetId).each(function(){
    var attributes = concatHashToString(this.attributes);
    var replacingStartTag = '<' + replaceWith + attributes +'>';
    var replacingEndTag = '</' + replaceWith + '>';
    $(this).replaceWith(replacingStartTag + $(this).html() + replacingEndTag);
  });
}
replaceElem('div','span');

/**
 * This function concats the attributes of old elements
 */
function concatHashToString(hash){
  var emptyStr = '';
  $.each(hash, function(index){
    emptyStr += ' ' + hash[index].name + '="' + hash[index].value + '"';
  });
  return emptyStr;
}

Related fiddle is in this link

Mellins answered 4/1, 2015 at 13:8 Comment(0)
G
2

You can use this function

var renameTag  = function renameTag($obj, new_tag) {
    var obj = $obj.get(0);
    var tag = obj.tagName.toLowerCase();
    var tag_start = new RegExp('^<' + tag);
    var tag_end = new RegExp('<\\/' + tag + '>$');
    var new_html = obj.outerHTML.replace(tag_start, "<" + new_tag).replace(tag_end, '</' + new_tag + '>');
    $obj.replaceWith(new_html);
};

ES6

const renameTag = function ($obj, new_tag) {
    let obj = $obj.get(0);
    let tag = obj.tagName.toLowerCase();
    let tag_start = new RegExp('^<' + tag);
    let tag_end = new RegExp('<\\/' + tag + '>$');
    let new_html = obj.outerHTML.replace(tag_start, "<" + new_tag).replace(tag_end, '</' + new_tag + '>');
    $obj.replaceWith(new_html);
};

Sample code

renameTag($(tr),'div');
Gerontology answered 21/12, 2017 at 4:8 Comment(0)
W
1

Since replaceWith() didn't work for me on an element basis (maybe because I used it inside map()), I did it by creating a new element and copying the attributes as needed.

$items = $('select option').map(function(){

  var
    $source = $(this),
    $copy = $('<li></li>'),
    title = $source.text().replace( /this/, 'that' );

  $copy
    .data( 'additional_info' , $source.val() )
    .text(title);

  return $copy;
});

$('ul').append($items);
Witt answered 30/4, 2014 at 21:18 Comment(0)
B
1

Take him by the word

Taken the Question by Word "how to change tag name?" I would suggest this solution:
If it makes sense or not has to be decided case by case.

My example will "rename" all a-Tags with hyperlinks for SMS with span tags. Maintaining all attributes and content:

$('a[href^="sms:"]').each(function(){
  var $t=$(this);
  var $new=$($t.wrap('<div>')
    .parent()
        .html()
        .replace(/^\s*<\s*a/g,'<span')
        .replace(/a\s*>\s*$/g,'span>')
        ).attr('href', null);
  $t.unwrap().replaceWith($new);
});

As it does not make any sense to have a span tag with an href attribute I remove that too. Doing it this way is bulletproof and compatible with all browsers that are supported by jquery. There are other ways people try to copy all the Attributes to the new Element, but those are not compatible with all browsers.

Although I think it is quite expensive to do it this way.

Barogram answered 9/10, 2014 at 18:39 Comment(0)
P
1

Jquery plugin to make "tagName" editable :

(function($){
    var $newTag = null;
    $.fn.tagName = function(newTag){
        this.each(function(i, el){
            var $el = $(el);
            $newTag = $("<" + newTag + ">");

            // attributes
            $.each(el.attributes, function(i, attribute){
                $newTag.attr(attribute.nodeName, attribute.nodeValue);
            });
            // content
            $newTag.html($el.html());

            $el.replaceWith($newTag);
        });
        return $newTag;
    };
})(jQuery);

See : http://jsfiddle.net/03gcnx9v/3/

Place answered 29/4, 2015 at 16:9 Comment(0)
V
1

Yet another script to change the node name

function switchElement() {
  $element.each(function (index, oldElement) {
    let $newElement = $('<' + nodeName + '/>');
    _.each($element[0].attributes, function(attribute) {
      $newElement.attr(attribute.name, attribute.value);
    });
    $element.wrapInner($newElement).children().first().unwrap();
  });
}

http://jsfiddle.net/rc296owo/5/

It will copy over the attributes and inner html into a new element and then replace the old one.

Vitality answered 13/5, 2016 at 9:31 Comment(0)
K
1

$(function(){
    $('#switch').bind('click', function(){
        $('p').each(function(){
        	$(this).replaceWith($('<div/>').html($(this).html()));
        });
    });
});
p {
    background-color: red;
}

div {
    background-color: yellow;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p>Hello</p>
<p>Hello2</p>
<p>Hello3</p>
<button id="switch">replace</button>
Kamerad answered 23/2, 2017 at 11:37 Comment(0)
A
1

Try this one also. in this example we can also have attributes of the old tag in new tag

var newName = document.querySelector('.test').outerHTML.replaceAll('h1', 'h2');
document.querySelector('.test').outerHTML = newName;
<h1 class="test">Replace H1 to H2</h1>
Airport answered 12/7, 2021 at 21:45 Comment(0)
P
1

Assume you enabled jQuery

  1. Get the Html-code of DOM.
  2. Replace the TAG in Html-code
  3. Convert Html-code to DOM

here comes the sample code, it is ugly, but work, lol.

DOM_old = $('<td>contents</td>');
temp = DOM_old[0].outerHTML;
temp = temp.replace('<td', '<div');
temp = temp.replace('</td>', '</div>');
DOM_new = $(temp);
Peristyle answered 30/12, 2022 at 6:3 Comment(0)
T
1

As the accepted answer have some limitations (like the attributes aren't migrated to the new element), I found a new way to replace tag name without loosing those. But it also have some limitations for example: The events set to the main element will not migrated to the new element. Anyways, I'm providing the function. Let me know if you have any better Idea.

With Pure Javascript:

function replaceTag(element, new_tag) {
  let outerHTML = element.outerHTML;
  let outerTag = outerHTML
    .match(/<([a-zA-Z]*?)( |>)/)[0]
    .replaceAll("<", "")
    .replaceAll("/", "")
    .replaceAll("=", "")
    .replaceAll(">", "")
    .trim();
  let newHTML_pre = outerHTML.replace(outerTag, new_tag);
  newHTML_pre = newHTML_pre.slice(0, newHTML_pre.length - outerTag.length - 3);
  let newHTML;
  if (outerHTML.endsWith('</' + outerTag + '>')) {
    newHTML = newHTML_pre + '</' + new_tag + '>';
  } else {
    newHTML = newHTML_pre;
  }
  element.outerHTML = newHTML;
}
// let e = document.querySelector('div');
// replaceTag(e, 'img');

With Jquery:

$.fn.replaceTag = function (new_tag) {
  return this.each(function () {
    let outerHTML = $(this).prop("outerHTML");
    let outerTag = outerHTML
      .match(/<([a-zA-Z]*?)( |>)/)[0]
      .replaceAll("<", "")
      .replaceAll("/", "")
      .replaceAll("=", "")
      .replaceAll(">", "")
      .trim();
    let newHTML_pre = outerHTML.replace(outerTag, new_tag);
    newHTML_pre = newHTML_pre.slice(0, newHTML_pre.length - outerTag.length - 3);
    let newHTML;
    if (outerHTML.endsWith("</" + outerTag + ">")) {
      newHTML = newHTML_pre + "</" + new_tag + ">";
    } else {
      newHTML = newHTML_pre;
    }
    $(this).prop("outerHTML", newHTML);
  });
};
// $('div').replaceTag('img');

Explanation:

The function replaces the start and end tag of the element's outerHTML with the new tag ignoring the child elements with the same tag name. Sometimes the element doesn't have end tag name like: (<div />), in that case it just replace the start tag. That's All.

Twofold answered 23/1 at 9:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.