javascript - ¿Cómo puedo cambiar el texto de un elemento sin cambiar sus elementos hijos?
Me gustaría actualizar el texto del elemento de forma dinámica:
<div>
**text to change**
<someChild>
text that should not change
</someChild>
<someChild>
text that should not change
</someChild>
</div>
Soy nuevo en jQuery, así que esta tarea me parece bastante desafiante. ¿Alguien podría indicarme una función/selector para usar?
Si es posible, me gustaría hacerlo sin agregar un nuevo contenedor para el texto que necesito cambiar.
Respuesta #1
Mark tiene una mejor solución usando jQuery, pero también podrías poder hacer esto en JavaScript normal.
En Javascript, la propiedad childNodes te da todos los nodos hijos de un elemento, incluidos los nodos de texto.
Entonces, si sabías que el texto que querías cambiar siempre iba a ser lo primero en el elemento, entonces dado por ejemplo este HTML:
<div id="your_div">
**text to change**
<p>
text that should not change
</p>
<p>
text that should not change
</p>
</div>
Podrías hacer esto:
var your_div = document.getElementById('your_div');
var text_to_change = your_div.childNodes[0];
text_to_change.nodeValue = 'new text';
Por supuesto, todavía puedes usar jQuery para seleccionar el <div> en primer lugar (es decir, var your_div=$ ('your_div').get(0);).
Respuesta #2
Actualización 2018
Dado que esta es una respuesta bastante popular, decidí actualizarla y embellecerla un poco agregando el selector textnode a jQuery como un complemento.
En el fragmento a continuación puedes ver que defino una nueva función de jQuery que obtiene todos (y solo) los nodos de texto. También puedes encadenar esta función, por ejemplo, con la función first(). Hago un trim en el nodo de texto y verifico que no esté vacío después del trim porque los espacios, tabulaciones, saltos de línea, etc., también son reconocidos como nodos de texto. Si necesitas esos nodos también, simplemente quítalo de la declaración if en la función de jQuery.
Agregué un ejemplo de cómo reemplazar el primer nodo de texto y cómo reemplazar todos los nodos de texto.
Este enfoque hace que sea más fácil leer el código y más fácil usarlo varias veces y con diferentes propósitos.
La Actualización 2017 (adrach) todavía debería funcionar igual si prefieres esa.
Como extensión de jQuery
//Add a jQuery extension so it can be used on any jQuery object
jQuery.fn.textNodes = function() {
return this.contents().filter(function() {
return (this.nodeType === Node.TEXT_NODE && this.nodeValue.trim() !== "");
});
}
//Use the jQuery extension
$(document).ready(function(){
$('#replaceAll').on('click', () => {
$('#testSubject').textNodes().replaceWith('Replaced');
});
$('#replaceFirst').on('click', () => {
$('#testSubject').textNodes().first().replaceWith('Replaced First');
});
});p {
margin: 0px;
}<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="testSubject">
**text to change**
<p>text that should not change</p>
<p>text that should not change</p>
**also text to change**
<p>text that should not change</p>
<p>text that should not change</p>
**last text to change**
</div>
<button id="replaceFirst">Replace First</button>
<button id="replaceAll">Replace All</button>Equivalente en Javascript (ES)
//Add a new function to the HTMLElement object so it can be used on any HTMLElement
HTMLElement.prototype.textNodes = function() {
return [...this.childNodes].filter((node) => {
return (node.nodeType === Node.TEXT_NODE && node.nodeValue.trim() !== "");
});
}
//Use the new HTMLElement function
document.addEventListener('DOMContentLoaded', () => {
document.querySelector('#replaceAll').addEventListener('click', () => {
document.querySelector('#testSubject').textNodes().forEach((node) => {
node.textContent = 'Replaced';
});
});
document.querySelector('#replaceFirst').addEventListener('click', function() {
document.querySelector('#testSubject').textNodes()[0].textContent = 'Replaced First';
});
});p {
margin: 0px;
}<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="testSubject">
**text to change**
<p>text that should not change</p>
<p>text that should not change</p>
**also text to change**
<p>text that should not change</p>
<p>text that should not change</p>
**last text to change**
</div>
<button id="replaceFirst">Replace First</button>
<button id="replaceAll">Replace All</button>Actualización 2017 (adrach):
Parece que varias cosas cambiaron desde que esto se publicó. Aquí hay una versión actualizada
$("div").contents().filter(function(){ return this.nodeType == 3; }).first().replaceWith("change text");
Respuesta original (No funciona para las versiones actuales)
$("div").contents().filter(function(){ return this.nodeType == 3; })
.filter(':first').text("change text");
Fuente: http://api.jquery.com/contents/
Respuesta #3
Ver en acción
Marcado :
$(function() {
$('input[type=button]').one('click', function() {
var cache = $('#parent').children();
$('#parent').text('Altered Text').append(cache);
});
});<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="parent">Some text
<div>Child1</div>
<div>Child2</div>
<div>Child3</div>
<div>Child4</div>
</div>
<input type="button" value="alter text" />Respuesta #4
Simplemente envuelve el texto que quieras cambiar en un span con una clase para seleccionar.
No necesariamente responde a tu pregunta, lo sé, pero probablemente sea una mejor práctica de codificación. Mantén las cosas limpias y simples
<div id="header">
<span class="my-text">**text to change**</span>
<div>
text that should not change
</div>
<div>
text that should not change
</div>
</div>
¡Voilà!
$('#header .mytext').text('New text here')
Respuesta #5
<div id="divtochange">
**text to change**
<div>text that should not change</div>
<div>text that should not change</div>
</div>
$(document).ready(function() {
$("#divtochange").contents().filter(function() {
return this.nodeType == 3;
})
.replaceWith("changed text");
});
Esto cambia solo el primer nodo de texto
