wake-up-neo.com

Datenattribut kann nicht mit der jQuery Data () - API festgelegt werden

Ich habe das folgende Feld in einer MVC-Ansicht:

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

In einer separaten js-Datei möchte ich das data-helptext-Attribut auf einen String-Wert setzen. Hier ist mein Code:

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

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

Der Aufruf alert() funktioniert einwandfrei, er zeigt den Text "Alter Text" in einem Alert-Dialog an. Der Aufruf, das data-helptext-Attribut auf "Testing 123" zu setzen, funktioniert jedoch nicht. "Alter Text" ist immer noch der aktuelle Wert des Attributs.

Benutze ich den Aufruf von data () falsch? Ich habe das im Web nachgeschlagen und kann nicht sehen, was ich falsch mache.

Hier ist das HTML-Markup:

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

Es wird in der .data() Dokumentation erwähnt

Die Datenattribute werden beim ersten Zugriff auf die Dateneigenschaft abgerufen und dann nicht mehr abgerufen oder mutiert (alle Datenwerte werden dann intern in jQuery gespeichert).

Dies wurde auch behandelt am Warum werden durch Änderungen an jQuery $ .fn.data () die entsprechenden HTML 5-Daten- * Attribute nicht aktualisiert?

Die Demo auf meiner ursprünglichen Antwort unten scheint nicht mehr zu funktionieren.

Aktualisierte Antwort

Wieder aus der .data() Dokumentation

Die Behandlung von Attributen mit eingebetteten Bindestrichen wurde in jQuery 1.6 geändert, um der W3C-HTML5-Spezifikation zu entsprechen.

Also für <div data-role="page"></div> ist das Folgende wahr $('div').data('role') === 'page'

Ich bin mir ziemlich sicher, dass $('div').data('data-role') in der Vergangenheit funktioniert hat, aber das scheint nicht mehr der Fall zu sein. Ich habe ein besseres Schaufenster erstellt, das sich in HTML protokolliert, anstatt die Konsole öffnen zu müssen, und camelCase ein zusätzliches Beispiel für den Bindestrich Datenattribute Konvertierung hinzugefügt.

Aktualisierte Demo (25.07.2015)

Siehe auch 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();

Ältere Demo


Ursprüngliche Antwort

Für diesen HTML:

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

und dieses JavaScript (mit 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;
});

Siehe Demo

Bei Verwendung der Chrome DevTools Konsole zum Überprüfen des DOM wird die $('#foo').data('helptext', 'Testing 123'); nicht aktualisiere den Wert wie in der Konsole angezeigt, aber $('#foo').attr('data-helptext', 'Testing 123'); tut dies.

239
andyb

Ich hatte ernsthafte Probleme mit

.data('property', value);

Das data-property-Attribut wurde nicht festgelegt.

Begonnen mit der Verwendung von jQuery .attr() :

Ruft den Wert eines Attributs für das erste Element in der Menge von .__ ab. übereinstimmende Elemente oder legen Sie ein oder mehrere Attribute für jeden übereinstimmenden Element.

.attr('property', value)

um den Wert einzustellen und

.attr('property')

um den Wert abzurufen.

Jetzt funktioniert es einfach!

34

@ andybs akzeptierte Antwort hat einen kleinen Fehler. Weiter zu meinem Kommentar zu seinem Beitrag oben ...

Für dieses HTML:

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

Sie müssen folgendermaßen auf das Attribut zugreifen:

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

aber die datenmethode wie folgt:

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

Das obige Update für die .data () -Methode verhindert "undefined" und der Datenwert wird aktualisiert (der HTML-Wert jedoch nicht).

Der Punkt des Attributs "Daten" besteht darin, einen Wert mit dem Element zu verbinden (oder zu "verknüpfen"). Sehr ähnlich dem onclick="alert('do_something')"-Attribut, das eine Aktion an das Element bindet ... Der Text ist unbrauchbar. Sie möchten nur, dass die Aktion funktioniert, wenn sie auf das Element klicken.

Sobald die Daten oder Aktionen an das Element gebunden sind, ist normalerweise * keine Notwendigkeit, den HTML-Code zu aktualisieren, nur die Daten oder die Methode, da dies Ihre Anwendung (JavaScript) verwenden würde. In Bezug auf die Leistung sehe ich nicht, warum Sie den HTML-Code sowieso auch aktualisieren möchten. Niemand sieht das HTML-Attribut (außer in Firebug oder anderen Konsolen).

Eine Möglichkeit, wie Sie darüber nachdenken sollten: HTML (zusammen mit Attributen) sind nur Text. Die von JavaScript verwendeten Daten, Funktionen, Objekte usw. befinden sich auf einer separaten Ebene. Nur wenn JavaScript dazu aufgefordert wird, liest oder aktualisiert es den HTML-Text, aber alle Daten und Funktionen, die Sie mit JavaScript erstellen, unterscheiden sich vollständig vom HTML-Text/den Attributen, die in Ihrer Firebug-Konsole (oder einer anderen Konsole) angezeigt werden.

* Ich lege den Schwerpunkt auf normalerweise , denn wenn Sie einen Fall haben, in dem Sie HTML-Code beibehalten und exportieren müssen (z. B. eine Art Mikroformat-/datengestützter Texteditor), in dem der HTML-Code frisch auf einer anderen Seite geladen wird, dann vielleicht Sie brauche auch das HTML aktualisiert.

8
Frank Forte

Ist mir gleich passiert. Es stellt sich heraus, dass 

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

gibt Ihnen ein nicht beschreibbares Objekt. Ich habe es gelöst mit:

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

Von da an war data ein beschreibbares Standard-JS-Objekt.

6
Nico

Um ein Angebot zu zitieren:

Die Datenattribute werden beim ersten Aufruf der Dateneigenschaft .__ abgerufen. auf den Zugriff wird dann nicht mehr zugegriffen oder mutiert (alle Datenwerte werden dann intern in jQuery gespeichert).

.data() - jQuery-Dokumentation

Beachten Sie, dass diese Einschränkung (ehrlich odd) nur für die Verwendung von .data() gilt.

Die Lösung? Verwenden Sie stattdessen .attr.

Natürlich fühlen sich einige von Ihnen unwohl, wenn Sie die dedizierte Methode nicht verwenden. Stellen Sie sich das folgende Szenario vor:

  • Der 'Standard' wird aktualisiert, so dass der Datenteil von benutzerdefinierten Attributen nicht mehr benötigt wird/ersetzt wird

Gesunder Menschenverstand - Warum würden sie ein bereits etabliertes Attribut so ändern? Stellen Sie sich vor, class beginne umbenannt in group und id in bezeichner. Das Internet würde brechen.

Und selbst dann hat Javascript die Möglichkeit, das Problem zu beheben. Und trotz seiner berüchtigten Inkompatibilität mit HTML können REGEX (und eine Reihe ähnlicher Methoden) Ihre Attribute schnell in diesen neuen mythischen "Standard" umbenennen.

TL; DR

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

Wie bereits erwähnt, kann die .data()-Methode weder den Wert des data--Attributs festlegen noch aktualisierte Werte lesen, wenn sich das data--Attribut ändert.

Meine Lösung bestand darin, jQuery um eine.realData()-Methode zu erweitern, die tatsächlich dem aktuellen Wert des Attributs entspricht:

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

HINWEIS: Sicherlich könnten Sie einfach .attr() verwenden, aber aus meiner Erfahrung machen die meisten Entwickler (auch bekannt als mir) den Fehler, .attr() und .data() als austauschbar anzusehen und ersetzen oft einen ohne den Gedanken. Es funktioniert zwar meistens, aber es ist eine großartige Möglichkeit, Fehler einzuführen, insbesondere wenn es um dynamische Datenbindungen geht. Durch die Verwendung von .realData() kann ich das beabsichtigte Verhalten genauer erklären.

1
Yarin

Hatte das gleiche Problem. Da Sie immer noch Daten mit der .data () -Methode erhalten können, müssen Sie nur einen Weg finden, in die Elemente zu schreiben. Dies ist die Hilfsmethode, die ich verwende. Wie die meisten Leute gesagt haben, müssen Sie .attr verwenden. Ich habe es, jedes _ durch zu ersetzen - wie ich weiß, tut es das. Ich kenne keine anderen Zeichen, die es ersetzt ... aber ich habe das nicht recherchiert. 

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

EDIT: 01.05.2017

Ich habe festgestellt, dass es immer noch Fälle gibt, in denen Sie mit integrierten Methoden nicht die korrekten Daten erhalten konnten. Daher verwende ich jetzt Folgendes:

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;
};
0
Matthew Pautzke