¿Usar jQuery para cambiar una etiqueta HTML?

130

es posible?

ejemplo:

$('a.change').click(function(){
//code to change p tag to h5 tag
});


<p>Hello!</p>
<a id="change">change</a>

Por lo tanto, hacer clic en el ancla de cambio debería hacer que la <p>Hello!</p>sección cambie (como ejemplo) a una etiqueta h5 para que termine <h5>Hello!</h5>después del clic. Me doy cuenta de que puede eliminar la etiqueta p y reemplazarla por una h5, pero ¿hay alguna forma de modificar realmente una etiqueta HTML?

Christopher Cooper
fuente

Respuestas:

211

Una vez que se crea un elemento dom, la etiqueta es inmutable, creo. Tendrías que hacer algo como esto:

$(this).replaceWith($('<h5>' + this.innerHTML + '</h5>'));
mishac
fuente
2
Vea mi comentario a continuación ... cambiar la estructura del documento para aplicar el estilo no es el mejor enfoque.
jrista
39
¿No sería este clobber los atributos que podrían estar en el elemento que reemplazó? Podría conducir a un comportamiento inesperado debido a los atributos de estilo eliminadas, atributos de datos, etc ...
Xavi
55
"<" + el.outerHTML.replace(/(^<\w+|\w+>$)/g, "H5") + ">";O función jQuery conectable: enlace
albahaca
65

Aquí hay una extensión que lo hará todo, en tantos elementos de la misma manera ...

Ejemplo de uso:

mantener la clase y los atributos existentes:

$('div#change').replaceTag('<span>', true);

o

Descarte la clase y los atributos existentes:

$('div#change').replaceTag('<span class=newclass>', false);

o incluso

reemplace todos los divs con tramos, copie clases y atributos, agregue un nombre de clase adicional

$('div').replaceTag($('<span>').addClass('wasDiv'), true);

Fuente del complemento:

$.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);
        });
    }
});
Orwellophile
fuente
2
Sip. Y para el registro, en realidad hay muchas razones muy válidas por las que es posible que desee cambiar una etiqueta. por ejemplo, si tenía etiquetas DIV dentro de un SPAN, que es hella no estándar. Esta función me ha servido mucho al trabajar con los estrictos estándares de princexml para la publicación de pdb.
Orwellophile
1
Se ve muy bien, aunque desafortunadamente pierde todos los eventos del elemento reemplazado. Quizás eso también podría ser manejado, ¡sería increíble!
NPC
@NPC así es la vida en la gran ciudad. Si va a reemplazar elementos, habrá víctimas. Estoy seguro de que hay alguien por ahí que conoce el jquery relevante para clonar los eventos :)
Orwellophile
1
@FrankvanLuijn @orwellophile en return node;realidad debería ser return this;como se muestra en la "versión anterior" del complemento. Esto es esencial para encadenar eventos juntos como$("tr:first").find("td").clone().replaceTag("li").appendTo("ul#list")
Cole Lawrence
1
No lo entiendo, ¿por qué necesitas 2 funciones? ¿Necesitas ambos? Lo siento, estoy perdido
João Pimentel Ferreira
12

En lugar de cambiar el tipo de etiqueta, debe cambiar el estilo de la etiqueta (o más bien, la etiqueta con una identificación específica). No es una buena práctica cambiar los elementos de su documento para aplicar cambios estilísticos. Prueba esto:

$('a.change').click(function() {
    $('p#changed').css("font-weight", "bold");
});

<p id="changed">Hello!</p>
<a id="change">change</a>
jrista
fuente
3
Incluso en este caso, no debería modificar la estructura de su documento. Si necesita mostrar una entrada en respuesta a un clic de edición, haga clic en la entrada y pegue la pantalla: ninguna o visibilidad: oculta en ella. Oculte el <h5> y muestre el <input> en respuesta al clic del botón. Si está modificando constantemente la estructura de su documento ... solo está pidiendo un montón de problemas de estilo y diseño en el futuro.
jrista
1
Absolutamente. Su javascript está incrustado o vinculado, por lo que si su preocupación es la seguridad, su enfoque de seguridad es algo defectuoso. Debe presentar el contenido de su documento de acuerdo con el rol del usuario ... combinar contenido para roles no es una forma segura de abordar el problema. Si alguien ha iniciado sesión en su sistema como administrador, presente el contenido para un administrador. Si han iniciado sesión en su sistema como lector, presente el contenido para un lector. Esto elimina completamente el contenido al que no se debe acceder. Una vez que se representa el contenido, use CSS para diseñar su documento y mostrar / ocultar cosas.
jrista
2
Estoy de acuerdo con usted y he tomado sus recomendaciones en el proyecto. Usaré toggle () para mostrar elementos de administración que solo se representan cuando un administrador inicia sesión. Aunque no está relacionado (directamente) con la pregunta original, esta es probablemente una mejor solución que la dirección en la que estaba yendo originalmente. ¡Salud!
Christopher Cooper
1
¡Cortejar! ¡Empaqué otro blop de mala seguridad! ¡Una victoria y rondas para todos! (inserte el icono de cerveza aquí)
jrista
1
Confiar en javascript del lado del cliente para la seguridad es realmente PEOR que no tener seguridad en absoluto. ¿Por qué? Porque crees que tienes seguridad, cuando en realidad no la tienes.
BryanH
8

Noté que la primera respuesta no era exactamente lo que necesitaba, así que hice un par de modificaciones y pensé que la publicaría aquí.

Mejorado replaceTag(<tagName>)

replaceTag(<tagName>, [withDataAndEvents], [withDataAndEvents])

Argumentos:

  • tagName: String
    • El nombre de la etiqueta, por ejemplo, "div", "span", etc.
  • withDataAndEvents: Boolean
    • "Un booleano que indica si los controladores de eventos deben copiarse junto con los elementos. A partir de jQuery 1.4, los datos del elemento también se copiarán". informacion
  • deepWithDataAndEvents: Boolean ,
    • Un booleano que indica si se deben copiar los controladores de eventos y los datos para todos los elementos secundarios del elemento clonado. Por defecto, su valor coincide con el valor del primer argumento (que por defecto es falso). " Info

Devoluciones:

Un elemento jQuery recién creado

Bien, sé que hay algunas respuestas aquí ahora, pero me encargué de escribir esto nuevamente.

Aquí podemos reemplazar la etiqueta de la misma manera que usamos la clonación. Estamos siguiendo la misma sintaxis que .clone () con withDataAndEventsy deepWithDataAndEventsque copia los datos y eventos de los nodos secundarios si se usan.

Ejemplo:

$tableRow.find("td").each(function() {
  $(this).clone().replaceTag("li").appendTo("ul#table-row-as-list");
});

Fuente:

$.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);
        })
    }
})

Tenga en cuenta que esto no reemplaza el elemento seleccionado, devuelve el elemento recién creado.

Cole Lawrence
fuente
2
Tenga en cuenta que .children()no incluirá ningún nodo de texto puro. Es posible que desee probar .contents()IIRC.
Orwellophile
5

La idea es envolver el elemento y desenvolver los contenidos:

function renameElement($element,newElement){

    $element.wrap("<"+newElement+">");
    $newElement = $element.parent();

    //Copying Attributes
    $.each($element.prop('attributes'), function() {
        $newElement.attr(this.name,this.value);
    });

    $element.contents().unwrap();       

    return $newElement;
}

Uso de la muestra:

renameElement($('p'),'h5');

Manifestación

Shubanker
fuente
0

Se me ocurrió un enfoque en el que usa una representación de cadena de su objeto jQuery y reemplaza el nombre de la etiqueta con expresiones regulares y JavaScript básico. No perderá ningún contenido y no tendrá que recorrer cada atributo / propiedad.

/*
 * 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);
}

Finalmente, puede reemplazar el objeto / nodo existente de la siguiente manera:

var $newElement = replaceTag($rankingSubmit, 'a');
$('#not-an-a-element').replaceWith($newElement);
kevinweber
fuente
0

Esta es mi solución Permite alternar entre etiquetas.

<!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>

zie1ony
fuente
0

Esta es la forma rápida de cambiar las etiquetas HTML dentro de su DOM usando jQuery. Creo que esta función replaceWith () es muy útil.

   var text= $('p').text();
   $('#change').on('click', function() {
     target.replaceWith( "<h5>"+text+"</h5>" );
   });
Mahafuz
fuente
0

Puede lograr por data-*atributo de esta data-replace="replaceTarget,replaceBy"manera con la ayuda de jQuery para obtener replaceTargety replaceByvalorar por .split()método después de obtener valores y luego usar el .replaceWith()método.
Esta data-*técnica de atributo permite administrar fácilmente cualquier reemplazo de etiquetas sin cambiar a continuación (código común para todos los reemplazos de etiquetas).

Espero que el siguiente fragmento te ayude mucho.

$(document).on('click', '[data-replace]', function(){
  var replaceTarget = $(this).attr('data-replace').split(',')[0];
  var replaceBy = $(this).attr('data-replace').split(',')[1];
  $(replaceTarget).replaceWith($(replaceBy).html($(replaceTarget).html()));
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<p id="abc">Hello World #1</p>
<a href="#" data-replace="#abc,<h1/>">P change with H1 tag</a>
<hr>
<h2 id="xyz">Hello World #2</h2>
<a href="#" data-replace="#xyz,<p/>">H1 change with P tag</a>
<hr>
<b id="bold">Hello World #2</b><br>
<a href="#" data-replace="#bold,<i/>">B change with I tag</a>
<hr>
<i id="italic">Hello World #2</i><br>
<a href="#" data-replace="#italic,<b/>">I change with B tag</a>

Raeesh Alam
fuente
0

La siguiente función hace el truco y mantiene todos los atributos. Lo usas por ejemplo así:changeTag("div", "p")

function changeTag(originTag, destTag) {
  while($(originTag).length) {
    $(originTag).replaceWith (function () {
      var attributes = $(this).prop("attributes");
      var $newEl = $(`<${destTag}>`)
      $.each(attributes, function() {
        $newEl.attr(this.name, this.value);
      });  
      return $newEl.html($(this).html())
    })
  }
}

Para asegurarse de que funciona, consulte el siguiente ejemplo

function changeTag(originTag, destTag) {
  while($(originTag).length) {
    $(originTag).replaceWith (function () {
      var attributes = $(this).prop("attributes");
      var $newEl = $(`<${destTag}>`)
      $.each(attributes, function() {
        $newEl.attr(this.name, this.value);
      });  
      return $newEl.html($(this).html())
    })
  }
}

changeTag("div", "p")

console.log($("body").html())
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<div class="A" style="font-size:1em">
  <div class="B" style="font-size:1.1em">A</div>
</div>
<div class="C" style="font-size:1.2em">
  B
</div>
</body>

João Pimentel Ferreira
fuente
-1

¿Hay alguna razón específica por la que necesita cambiar la etiqueta? Si solo desea agrandar el texto, cambiar la clase CSS de la etiqueta p sería una mejor manera de hacerlo.

Algo como esto:

$('#change').click(function(){
  $('p').addClass('emphasis');
});
Dave Ward
fuente
La razón por la que solicito cambiar el elemento / etiqueta es porque estoy intentando cambiar una etiqueta (un <h5>, aunque el tipo es irrelevante) a un <input> cuando se hace clic en un botón "editar" en otra parte de la página .
Christopher Cooper