Impossibile impostare l'attributo di dati utilizzando l'API jQuery Data ()


131

Ho il seguente campo in una vista MVC:

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

In un file js separato, voglio impostare l' data-helptextattributo su un valore di stringa. Ecco il mio codice:

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

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

La alert()chiamata funziona bene, mostra il testo "Vecchio testo" in una finestra di avviso. Tuttavia, la chiamata per impostare l' data-helptextattributo su "Test 123" non funziona. "Vecchio testo" è ancora il valore corrente dell'attributo.

Sto usando la chiamata a dati () in modo errato? L'ho cercato sul web e non riesco a vedere cosa sto facendo di sbagliato.

Ecco il markup HTML:

<input data-helptext="Old Text" id="Course_Title" name="Course.Title" type="text" value="" />

Il codice sembra OK. Nessun problema in questa demo . Quale versione di jQuery stai usando?
Andyb,

Sto usando 1.5.1 fornito con il modello di progetto ASP NET MVC. Potrebbe essere che devo aggiornare jQuery?
Jason Evans,

OK, allora non è la versione di jQuery. Stavo pensando che potrebbe essere una versione davvero vecchia. L'API data () che stai utilizzando è stata aggiunta in v1.2.3
andyb il

Potresti aggiungere il markup per favore? Stai usando un data-attributo HTML5 personalizzato ?
Andyb,

Come stai osservando il valore? jQuery non reimposta il valore sul DOM, sebbene lo aggiorni correttamente. Vedi la mia risposta qui sotto per un test e una spiegazione
Andyb,

Risposte:


239

È menzionato nella .data()documentazione

Gli attributi dei dati vengono estratti la prima volta che si accede alla proprietà dei dati e quindi non si accede più o si modifica (tutti i valori dei dati vengono quindi memorizzati internamente in jQuery)

Questo è stato trattato anche su Perché le modifiche a jQuery $ .fn.data () non aggiornano gli attributi html 5 data- * corrispondenti?

La demo sulla mia risposta originale qui sotto non sembra funzionare più.

Risposta aggiornata

Ancora una volta, dalla .data()documentazione

Il trattamento degli attributi con trattini incorporati è stato modificato in jQuery 1.6 per renderlo conforme alla specifica HTML5 del W3C.

Quindi per <div data-role="page"></div>quanto segue è vero$('div').data('role') === 'page'

Sono abbastanza sicuro che abbia $('div').data('data-role')funzionato in passato ma non sembra più essere così. Ho creato una vetrina migliore che accede a HTML anziché dover aprire la console e ho aggiunto un ulteriore esempio del multi-trattino alla conversione degli attributi di dati di camelCase .

Demo aggiornata (25/07/2015)

Vedi anche jQuery Data vs Attr?

HTML

<div id="changeMe" data-key="luke" data-another-key="vader"></div>
<a href="#" id="changeData"></a>
<table id="log">
    <tr><th>Setter</th><th>Getter</th><th>Result of calling getter</th><th>Notes</th></tr>
</table>

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('<tr><td><code>' + setter + '</code></td><td><code>' + getter + '</code></td><td>' + result + '</td><td>' + note + '</td></tr>');
})('', ".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 <code>key</code>)");
    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 <code>data-another-key</code>");
    logger(".data('another-key')", ".data('another-key')", "jQuery < 1.6 get multi hyphen <code>data-another-key</code> (also supported in jQuery 1.6+)");

    return false;
});

$('#changeData').click();

Demo precedente


Risposta originale

Per questo HTML:

<div id="foo" data-helptext="bar"></div>
<a href="#" id="changeData">change data value</a>

e questo 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;
});

Vedi la demo

Utilizzando Chrome DevTools Console per ispezionare il DOM, $('#foo').data('helptext', 'Testing 123'); non aggiorna il valore come visto nella Console ma lo $('#foo').attr('data-helptext', 'Testing 123');fa.


1
Non sono sicuro di cosa sia cambiato, ma la demo del violino ritorna indefinita nella console di Chrome
manubkk

Allora, qual è lo scopo di jQuery che ti consente di inserire un secondo argomento? Per aggiornare il valore memorizzato nella cache delle variabili js?
ahnbizcad,

@gwho Non sono sicuro di aver compreso completamente la tua domanda, ma presumo che ti riferisca alla risposta originale del 2011 usando jQuery 1.6.2. Se è così, allora il. data('key', 'value')metodo fa aggiornare il valore nella cache jQuery, ma per motivi di prestazioni (immagino DOM mutazione) il DOM in sé non viene aggiornato.
Andyb,

2
quindi se volessi aggiornare il DOM, dovresti farlo .attr('key','value')indipendentemente dal fatto .data('key', 'value'), vero? Mi sembra ridondante, e ho difficoltà a immaginare uno scenario in cui vorresti scrivere sul DOM memorizzato nella cache, ma non sul vero DOM. Forse non capisco la cache di jQuery; Quindi un visitatore vedrebbe tutte le cose che si .data()modificano sul proprio schermo o no?
ahnbizcad,

1
Quindi non è solo una questione di prestazioni; non possono essere paragonati. Hanno scopi completamente diversi e cambiano diverse "versioni" del DOM. Quindi torniamo alla domanda: che senso ha usare .data () se devi fare .attr () per cambiare il DOM ACUTAL? sembra ridondante.
ahnbizcad,

34

Stavo avendo seri problemi con

.data('property', value);

Non stava impostando l' data-propertyattributo.

Iniziato a usare jQuery .attr():

Ottieni il valore di un attributo per il primo elemento nell'insieme di elementi corrispondenti o imposta uno o più attributi per ogni elemento corrispondente.

.attr('property', value)

per impostare il valore e

.attr('property')

per recuperare il valore.

Ora funziona e basta!


1
Per me sono stato in grado di modificare la proprietà dei dati con data () ma ho notato negli strumenti di sviluppo che non mostrava la modifica, quindi per questo motivo sono andato con attr ()
drooh il

8

La risposta accettata di @ andyb ha un piccolo bug. A seguito del mio commento sul suo post sopra ...

Per questo HTML:

<div id="foo" data-helptext="bar"></div>
<a href="#" id="changeData">change data value</a>

Devi accedere all'attributo in questo modo:

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

ma il metodo di dati in questo modo:

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

La correzione precedente per il metodo .data () impedirà "non definito" e il valore dei dati verrà aggiornato (mentre l'HTML non lo farà)

Il punto dell'attributo "dati" è di associare (o "collegare") un valore con l'elemento. Molto simile alonclick="alert('do_something')" all'attributo, che lega un'azione all'elemento ... il testo è inutile, vuoi solo che l'azione funzioni quando fanno clic sull'elemento.

Una volta che i dati o l'azione sono associati all'elemento, di solito * non è necessario aggiornare l'HTML, solo i dati o il metodo, poiché è quello che userebbe l'applicazione (JavaScript). Per quanto riguarda le prestazioni, non vedo perché dovresti aggiornare comunque l'HTML, nessuno vede l'attributo html (tranne in Firebug o altre console).

Un modo in cui potresti pensarci: l'HTML (insieme agli attributi) sono solo testo. I dati, le funzioni, gli oggetti, ecc. Utilizzati da JavaScript esistono su un piano separato. Solo quando viene richiesto a JavaScript di farlo, leggerà o aggiornerà il testo HTML, ma tutti i dati e le funzionalità che crei con JavaScript agiscono completamente separati dal testo / dagli attributi HTML che vedi nella tua console Firebug (o altro).

* Metto l'accento di solito perché se hai un caso in cui è necessario conservare ed esportare HTML (ad es. Un qualche tipo di editor di testo con micro formato / dati) in cui l'HTML verrà caricato fresco su un'altra pagina, allora forse hai bisogno dell'aggiornamento HTML pure.


Grazie. Questo ha aiutato, tra tutte le altre risposte con esempi errati! Il datain attr('data-helptext'fa la differenza, in cui la risposta accettata e quelle con molti voti non funzionano. +1
Aleks,

6

È successo lo stesso per me. Si scopre che

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

ti dà un oggetto non scrivibile. L'ho risolto usando:

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

E da quel momento in poi, è datastato un oggetto JS standard e scrivibile.


Come ci scrivi allora?
Lavora per vivere il

Scusa Thom, non so che cosa intendi ... Dopo averlo fatto $.extend..., puoi usare datacome preferisci: data.name = 'Nico'; data.questionSolved = true;e console.log(data)mostrerò queste proprietà aggiunte di recente
Nico

3

Per citare un preventivo:

Gli attributi dei dati vengono estratti la prima volta che si accede alla proprietà dei dati e quindi non si accede più o si modifica (tutti i valori dei dati vengono quindi memorizzati internamente in jQuery).

.data() - Documentazione jQuery

Si noti che questa limitazione (francamente dispari ) è negata solo all'utilizzo di .data().

La soluzione? Uso.attr invece.

Naturalmente, molti di voi potrebbero sentirsi a disagio nel non usare il suo metodo dedicato. Considera il seguente scenario:

  • Lo "standard" viene aggiornato in modo che la parte di dati degli attributi personalizzati non sia più richiesta / venga sostituita

Buon senso - Perché dovrebbero cambiare un attributo già stabilito in quel modo? Immagina di classiniziare rinominato in gruppo e idin identificatore . Internet si spezzerebbe.

E anche allora, Javascript stesso ha la capacità di risolvere questo problema - E ovviamente, nonostante sia la famigerata incompatibilità con HTML, REGEX (e una varietà di metodi simili) potrebbe rapidamente rinominare i tuoi attributi in questo nuovo "mitico" standard.

TL; DR

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

1

Come accennato, il .data()metodo in realtà non imposterà il valore data-dell'attributo, né leggerà i valori aggiornati se ildata- attributo cambia.

La mia soluzione era estendere jQuery con un .realData()metodo che corrisponda effettivamente al valore corrente dell'attributo:

// Alternative to .data() that updates data- attributes, and reads their current value.
(function($){
  $.fn.realData = function(name,value) {
      if (value === undefined) {
        return $(this).attr('data-'+name);
      } else {
        $(this).attr('data-'+name,value);
      }
  };
})(jQuery);

NOTA: Sicuro che potresti semplicemente usare .attr(), ma dalla mia esperienza, la maggior parte degli sviluppatori (aka me) commette l'errore di visualizzazione .attr()e .data()come intercambiabile, e spesso sostituisce l'uno all'altro senza pensare. Potrebbe funzionare la maggior parte delle volte, ma è un ottimo modo per introdurre bug, specialmente quando si tratta di qualsiasi tipo di associazione dinamica dei dati. Quindi .realData(), usando , posso essere più esplicito sul comportamento previsto.


0

Ho avuto lo stesso problema. Dato che puoi ancora ottenere dati usando il metodo .data (), devi solo trovare un modo per scrivere sugli elementi. Questo è il metodo di supporto che uso. Come molte persone hanno detto, dovrai usare .attr. L'ho sostituito con qualsiasi _ con - come so che lo fa. Non sono a conoscenza di altri personaggi che sostituisce ... tuttavia non l'ho studiato.

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]);
    }
}

MODIFICA: 5/1/2017

Ho scoperto che c'erano ancora casi in cui non era possibile ottenere i dati corretti utilizzando i metodi integrati, quindi quello che uso ora è il seguente:

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;
};
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.