Is this possible?
example:
$(\'a.change\').click(function(){
//code to change p tag to h5 tag
});
<p>Hello!</p>
<a id=\"change\">change</a>
So clicking the change anchor should cause the <p>Hello!</p>
section to change to (as an example) an h5 tag so you\'d end up with <h5>Hello!</h5>
after the click. I realize you can delete the p tag and replace it with an h5, but is there anyway to actually modify an HTML tag?
Once a dom element is created, the tag is immutable, I believe. You\'d have to do something like this:
$(this).replaceWith($(\'<h5>\' + this.innerHTML + \'</h5>\'));
Here\'s an extension that will do it all, on as many elements in as many ways...
Example usage:
keep existing class and attributes:
$(\'div#change\').replaceTag(\'<span>\', true);
or
Discard existing class and attributes:
$(\'div#change\').replaceTag(\'<span class=newclass>\', false);
or even
replace all divs with spans, copy classes and attributes, add extra class name
$(\'div\').replaceTag($(\'<span>\').addClass(\'wasDiv\'), true);
Plugin Source:
$.extend({
replaceTag: function (currentElem, newTagObj, keepProps) {
var $currentElem = $(currentElem);
var i, $newTag = $(newTagObj).clone();
if (keepProps) {//{{{
newTag = $newTag[0];
newTag.className = currentElem.className;
$.extend(newTag.classList, currentElem.classList);
$.extend(newTag.attributes, currentElem.attributes);
}//}}}
$currentElem.wrapAll($newTag);
$currentElem.contents().unwrap();
// return node; (Error spotted by Frank van Luijn)
return this; // Suggested by ColeLawrence
}
});
$.fn.extend({
replaceTag: function (newTagObj, keepProps) {
// \"return\" suggested by ColeLawrence
return this.each(function() {
jQuery.replaceTag(this, newTagObj, keepProps);
});
}
});
Rather than change the type of tag, you should be changing the style of the tag (or rather, the tag with a specific id.) Its not a good practice to be changing the elements of your document to apply stylistic changes. Try this:
$(\'a.change\').click(function() {
$(\'p#changed\').css(\"font-weight\", \"bold\");
});
<p id=\"changed\">Hello!</p>
<a id=\"change\">change</a>
I noticed that the first answer wasn\'t quite what I needed, so I made a couple of modifications and figured I\'d post it back here.
Improved replaceTag(<tagName>)
replaceTag(<tagName>, [withDataAndEvents], [withDataAndEvents])
Arguments:
- tagName: String
- The tag name e.g. \"div\", \"span\", etc.
- withDataAndEvents: Boolean
- \"A Boolean indicating whether event handlers should be copied along with the elements. As of jQuery 1.4, element data will be copied as well.\" info
- deepWithDataAndEvents: Boolean,
- A Boolean indicating whether event handlers and data for all children of the cloned element should be copied. By default its value matches the first argument\'s value (which defaults to false).\" info
Returns:
A newly created jQuery element
Okay, I know there are a few answers here now, but I took it upon myself to write this again.
Here we can replace the tag in the same way we use cloning.
We are following the same syntax as .clone() with the withDataAndEvents
and deepWithDataAndEvents
which copy the child nodes\' data and events if used.
Example:
$tableRow.find(\"td\").each(function() {
$(this).clone().replaceTag(\"li\").appendTo(\"ul#table-row-as-list\");
});
Source:
$.extend({
replaceTag: function (element, tagName, withDataAndEvents, deepWithDataAndEvents) {
var newTag = $(\"<\" + tagName + \">\")[0];
// From [Stackoverflow: Copy all Attributes](http://stackoverflow.com/a/6753486/2096729)
$.each(element.attributes, function() {
newTag.setAttribute(this.name, this.value);
});
$(element).children().clone(withDataAndEvents, deepWithDataAndEvents).appendTo(newTag);
return newTag;
}
})
$.fn.extend({
replaceTag: function (tagName, withDataAndEvents, deepWithDataAndEvents) {
// Use map to reconstruct the selector with newly created elements
return this.map(function() {
return jQuery.replaceTag(this, tagName, withDataAndEvents, deepWithDataAndEvents);
})
}
})
Note that this does not replace the selected element, it returns the newly created one.
I came up with an approach where you use a string representation of your jQuery object and replace the tag name using regular expressions and basic JavaScript. You will not loose any content and don\'t have to loop over each attribute/property.
/*
* replaceTag
* @return {$object} a new object with replaced opening and closing tag
*/
function replaceTag($element, newTagName) {
// Identify opening and closing tag
var oldTagName = $element[0].nodeName,
elementString = $element[0].outerHTML,
openingRegex = new RegExp(\"^(<\" + oldTagName + \" )\", \"i\"),
openingTag = elementString.match(openingRegex),
closingRegex = new RegExp(\"(<\\/\" + oldTagName + \">)$\", \"i\"),
closingTag = elementString.match(closingRegex);
if (openingTag && closingTag && newTagName) {
// Remove opening tag
elementString = elementString.slice(openingTag[0].length);
// Remove closing tag
elementString = elementString.slice(0, -(closingTag[0].length));
// Add new tags
elementString = \"<\" + newTagName + \" \" + elementString + \"</\" + newTagName + \">\";
}
return $(elementString);
}
Finally, you can replace the existing object/node as follows:
var $newElement = replaceTag($rankingSubmit, \'a\');
$(\'#not-an-a-element\').replaceWith($newElement);
This is my solution. It allows to toggle between tags.
<!DOCTYPE html>
<html>
<head>
<title></title>
<script src=\"https://code.jquery.com/jquery-1.11.3.js\"></script>
<script type=\"text/javascript\">
function wrapClass(klass){
return \'to-\' + klass;
}
function replaceTag(fromTag, toTag){
/** Create selector for all elements you want to change.
* These should be in form: <fromTag class=\"to-toTag\"></fromTag>
*/
var currentSelector = fromTag + \'.\' + wrapClass(toTag);
/** Select all elements */
var $selected = $(currentSelector);
/** If you found something then do the magic. */
if($selected.size() > 0){
/** Replace all selected elements */
$selected.each(function(){
/** jQuery current element. */
var $this = $(this);
/** Remove class \"to-toTag\". It is no longer needed. */
$this.removeClass(wrapClass(toTag));
/** Create elements that will be places instead of current one. */
var $newElem = $(\'<\' + toTag + \'>\');
/** Copy all attributes from old element to new one. */
var attributes = $this.prop(\"attributes\");
$.each(attributes, function(){
$newElem.attr(this.name, this.value);
});
/** Add class \"to-fromTag\" so you can remember it. */
$newElem.addClass(wrapClass(fromTag));
/** Place content of current element to new element. */
$newElem.html($this.html());
/** Replace old with new. */
$this.replaceWith($newElem);
});
/** It is possible that current element has desired elements inside.
* If so you need to look again for them.
*/
replaceTag(fromTag, toTag);
}
}
</script>
<style type=\"text/css\">
section {
background-color: yellow;
}
div {
background-color: red;
}
.big {
font-size: 40px;
}
</style>
</head>
<body>
<button onclick=\"replaceTag(\'div\', \'section\');\">Section -> Div</button>
<button onclick=\"replaceTag(\'section\', \'div\');\">Div -> Section</button>
<div class=\"to-section\">
<p>Matrix has you!</p>
<div class=\"to-section big\">
<p>Matrix has you inside!</p>
</div>
</div>
<div class=\"to-section big\">
<p>Matrix has me too!</p>
</div>
</body>
</html>
Is there a specific reason that you need to change the tag? If you just want to make the text bigger, changing the p tag\'s CSS class would be a better way to go about that.
Something like this:
$(\'#change\').click(function(){
$(\'p\').addClass(\'emphasis\');
});