No se puede establecer el atributo de datos usando la API jQuery Data ()

Tengo el siguiente campo en una vista de MVC:

@Html.TextBoxFor(model => model.Course.Title, new { data_helptext = "Old Text" }) 

En un archivo js separado, quiero establecer el atributo de data-helptext en un valor de cadena. Aquí está mi código:

 alert($(targetField).data("helptext")); $(targetField).data("helptext", "Testing 123"); 

La llamada de alert() funciona bien, muestra el texto “Texto antiguo” en un cuadro de diálogo de alerta. Sin embargo, la llamada para establecer el atributo de data-helptext a “Prueba 123” no funciona. “Texto antiguo” sigue siendo el valor actual del atributo.

¿Estoy utilizando la llamada a data () incorrectamente? He buscado esto en la web, y no puedo ver lo que estoy haciendo mal.

Aquí está el marcado HTML:

  

Se menciona en la documentación de .data()

Los atributos de datos se extraen la primera vez que se accede a la propiedad de los datos y luego ya no se accede a ellos ni se los muda (todos los valores de los datos se almacenan internamente en jQuery)

Esto también se cubrió en ¿Por qué los cambios en jQuery $ .fn.data () no actualizan los atributos html 5 data- * correspondientes?

La demostración en mi respuesta original a continuación no parece funcionar más.

Respuesta actualizada

De nuevo, desde la documentación de .data()

El tratamiento de los atributos con guiones incrustados se modificó en jQuery 1.6 para cumplir con la especificación W3C HTML5.

Entonces para

lo siguiente es verdadero $('div').data('role') === 'page'

Estoy bastante seguro de que $('div').data('data-role') funcionó en el pasado, pero ese ya no parece ser el caso. Creé un escaparate mejor que se registra en HTML en lugar de tener que abrir la consola y agregué un ejemplo adicional de la conversión de atributos de datos camelCase de múltiples guiones.

Demo actualizada (25-07-2015)

Ver también jQuery Data vs Attr?

HTML

 
SetterGetterResult of calling getterNotes

JavaScript (jQuery 1.6.2+)

 var $changeMe = $('#changeMe'); var $log = $('#log'); var logger; (logger = function(setter, getter, note) { note = note || ''; eval('$changeMe' + setter); var result = eval('$changeMe' + getter); $log.append('' + setter + '' + getter + '' + result + '' + note + ''); })('', ".data('key')", "Initial value"); $('#changeData').click(function() { // set data-key to new value logger(".data('key', 'leia')", ".data('key')", "expect leia on jQuery node object but DOM stays as luke"); // try and set data-key via .attr and get via some methods logger(".attr('data-key', 'yoda')", ".data('key')", "expect leia (still) on jQuery object but DOM now yoda"); logger("", ".attr('key')", "expect undefined (no attr key)"); logger("", ".attr('data-key')", "expect yoda in DOM and on jQuery object"); // bonus points logger('', ".data('data-key')", "expect undefined (cannot get via this method)"); logger(".data('anotherKey')", ".data('anotherKey')", "jQuery 1.6+ get multi hyphen data-another-key"); logger(".data('another-key')", ".data('another-key')", "jQuery < 1.6 get multi hyphen data-another-key (also supported in jQuery 1.6+)"); return false; }); $('#changeData').click(); 

Demo anterior


Respuesta original

Para este HTML:

 
change data value

y este JavaScript (con jQuery 1.6.2)

 console.log($('#foo').data('helptext')); $('#changeData').click(function() { $('#foo').data('helptext', 'Testing 123'); // $('#foo').attr('data-helptext', 'Testing 123'); console.log($('#foo').data('data-helptext')); return false; }); 

Ver demostración

Usando la consola de Chrome DevTools para inspeccionar el DOM, los $('#foo').data('helptext', 'Testing 123'); no actualiza el valor como se ve en la consola, pero $('#foo').attr('data-helptext', 'Testing 123'); hace.

Estaba teniendo serios problemas con

 .data('property', value); 

No estaba configurando el atributo de data-property .

.attr() usar .attr() jQuery:

Obtenga el valor de un atributo para el primer elemento en el conjunto de elementos coincidentes o establezca uno o más atributos para cada elemento coincidente.

 .attr('property', value) 

para establecer el valor y

 .attr('property') 

para recuperar el valor

¡Ahora solo funciona!

La respuesta aceptada de @andyb tiene un pequeño error. Además de mi comentario sobre su publicación anterior …

Para este HTML:

 
change data value

Necesita acceder al atributo de esta manera:

 $('#foo').attr('data-helptext', 'Testing 123'); 

pero el método de datos de esta manera:

 $('#foo').data('helptext', 'Testing 123'); 

La solución anterior para el método .data () impedirá “indefinido” y el valor de los datos se actualizará (mientras que el HTML no lo hará)

El punto del atributo “datos” es vincular (o “vincular”) un valor con el elemento. Muy similar al atributo onclick="alert('do_something')" , que vincula una acción al elemento … el texto es inútil, solo desea que la acción funcione cuando hacen clic en el elemento.

Una vez que los datos o la acción están vinculados al elemento, por lo general * no es necesario actualizar el HTML, solo los datos o el método, ya que eso es lo que usaría su aplicación (JavaScript). En cuanto al rendimiento, no veo por qué querrías actualizar el HTML de todos modos, nadie ve el atributo html (excepto en Firebug u otras consolas).

Una forma en que podría querer pensar sobre esto: el HTML (junto con los atributos) son solo texto. Los datos, funciones, objetos, etc. que usa JavaScript existen en un plano separado. Solo cuando se le indique a JavaScript que lo haga, leerá o actualizará el texto HTML, pero todos los datos y funcionalidades que cree con JavaScript están actuando de manera completamente independiente del texto / atributos HTML que ve en su consola Firebug (u otra).

* Pongo énfasis en general porque si tienes un caso donde necesitas preservar y exportar HTML (por ejemplo, algún tipo de editor de texto con formato micro / datos) donde el HTML se cargará en otra página, entonces tal vez necesites actualizar el HTML también.

Me pasó lo mismo. Resulta que

 var data = $("#myObject").data(); 

te da un objeto no modificable Lo resolví usando:

 var data = $.extend({}, $("#myObject").data()); 

Y a partir de ese momento, los data eran un objeto JS estándar y escribible.

Para citar una cita:

Los atributos de datos se obtienen la primera vez que se accede a la propiedad de los datos y luego ya no se accede a ellos ni se los muda (todos los valores de los datos se almacenan internamente en jQuery).

.data() – jQuery Documentiation

Tenga en cuenta que esta limitación (francamente impar ) solo se retendrá al uso de .data() .

¿La solución? Use .attr en .attr lugar.

Por supuesto, muchos de ustedes pueden sentirse incómodos al no usar su método dedicado. Considere la siguiente situación:

  • El ‘estándar’ se actualiza para que la porción de datos de los atributos personalizados ya no sea necesaria / se reemplace

Sentido común: ¿por qué cambiarían un atributo ya establecido como ese? Solo imagine que la class comienza a renombrarse como grupo e id a identificador . Internet se romperá.

Y aun así, el Javascript tiene la capacidad de solucionarlo. Y, por supuesto, a pesar de su infame incompatibilidad con HTML, REGEX (y una variedad de métodos similares) podría cambiar rápidamente el nombre de sus atributos a este nuevo “mítico” estándar.

TL; DR

 alert($(targetField).attr("data-helptext")); 

Tenía el mismo problema. Como todavía puede obtener datos utilizando el método .data (), solo tiene que encontrar la manera de escribir en los elementos. Este es el método de ayuda que uso. Como la mayoría de las personas han dicho, tendrás que usar .attr. Lo tengo reemplazando cualquier _ por – como sé que hace eso. No conozco ningún otro personaje al que sustituya … sin embargo, no he investigado eso.

 function ExtendElementData(element, object){ //element is what you want to set data on //object is a hash/js-object var keys = Object.keys(object); for (var i = 0; i < keys.length; i++){ var key = keys[i]; $(element).attr('data-'+key.replace("_", "-"), object[key]); } } 

EDITAR: 5/1/2017

Descubrí que aún había casos en los que no se podían obtener los datos correctos con los métodos integrados, por lo que lo que uso ahora es el siguiente:

 function setDomData(element, object){ //object is a hash var keys = Object.keys(object); for (var i = 0; i < keys.length; i++){ var key = keys[i]; $(element).attr('data-'+key.replace("_", "-"), object[key]); } }; function getDomData(element, key){ var domObject = $(element).get(0); var attKeys = Object.keys(domObject.attributes); var values = null; if (key != null){ values = $(element).attr('data-' + key); } else { values = {}; var keys = []; for (var i = 0; i < attKeys.length; i++) { keys.push(domObject.attributes[attKeys[i]]); } for (var i = 0; i < keys.length; i++){ if(!keys[i].match(/data-.*/)){ values[keys[i]] = $(element).attr(keys[i]); } } } return values; };