Tidak dapat menetapkan atribut data menggunakan API jQuery Data ()

131

Saya memiliki bidang berikut pada tampilan MVC:

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

Dalam file js terpisah, saya ingin mengatur data-helptextatribut ke nilai string. Ini kode saya:

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

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

The alert()panggilan bekerja dengan baik, hal itu menunjukkan teks "Old Text" dalam dialog peringatan. Namun, panggilan untuk mengatur data-helptextatribut ke "Testing 123" tidak berfungsi. "Teks Lama" masih merupakan nilai atribut saat ini.

Apakah saya menggunakan panggilan ke data () secara salah? Saya sudah mencari ini di web, dan saya tidak bisa melihat kesalahan saya.

Ini markup HTML:

<input data-helptext="Old Text" id="Course_Title" name="Course.Title" type="text" value="" />
Jason Evans
sumber
Kode terlihat OK. Tidak ada masalah dalam demo ini . Versi jQuery mana yang Anda gunakan?
andyb
Saya menggunakan 1.5.1 yang datang dengan template proyek ASP NET MVC. Mungkinkah saya perlu memperbarui jQuery?
Jason Evans
OK, itu bukan versi jQuery. Saya berpikir itu mungkin versi yang sangat lama. API data () yang Anda gunakan telah ditambahkan di v1.2.3
andyb
Bisakah Anda menambahkan markup? Apakah Anda menggunakan data-atribut HTML5 khusus ?
andyb
Bagaimana Anda mengamati nilainya? jQuery tidak mempertahankan nilai kembali ke DOM, meskipun tidak benar memperbaruinya. Lihat jawaban saya di bawah ini untuk ujian dan penjelasan
andyb

Jawaban:

239

Itu disebutkan dalam .data()dokumentasi

Atribut data ditarik pertama kali properti data diakses dan kemudian tidak lagi diakses atau dimutasi (semua nilai data kemudian disimpan secara internal di jQuery)

Ini juga dibahas pada Mengapa tidak mengubah ke jQuery $ .fn.data () memperbarui atribut html 5 data- * yang sesuai?

Demo pada jawaban asli saya di bawah ini sepertinya tidak berfungsi lagi.

Jawaban yang diperbarui

Sekali lagi, dari .data()dokumentasi

Perlakuan atribut dengan tanda hubung tertanam diubah di jQuery 1.6 agar sesuai dengan spesifikasi W3C HTML5.

Jadi untuk <div data-role="page"></div>yang berikut ini benar$('div').data('role') === 'page'

Saya cukup yakin itu $('div').data('data-role')berhasil di masa lalu tetapi tampaknya tidak menjadi masalah lagi. Saya telah membuat showcase yang lebih baik yang log ke HTML daripada harus membuka Konsol dan menambahkan contoh tambahan dari multi-hyphen ke konversi atribut data camelCase .

Demo yang diperbarui (2015-07-25)

Juga lihat 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 yang lebih lama


Jawaban asli

Untuk HTML ini:

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

dan JavaScript ini (dengan 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;
});

Lihat demo

Menggunakan Chrome DevTools Console untuk memeriksa DOM, $('#foo').data('helptext', 'Testing 123'); tidak memperbarui nilai seperti yang terlihat di Konsol tetapi $('#foo').attr('data-helptext', 'Testing 123');tidak.

andyb
sumber
1
Tidak yakin apa yang telah berubah, tetapi demo biola Anda kembali tidak terdefinisi di konsol chrome
manubkk
Jadi, apa gunanya jQuery memungkinkan Anda untuk mengajukan argumen kedua? Untuk memperbarui nilai yang disimpan dalam cache variabel js?
ahnbizcad
@ gwho Saya tidak yakin saya benar-benar mengerti pertanyaan Anda, tapi saya berasumsi Anda merujuk ke jawaban asli dari 2011 menggunakan jQuery 1.6.2. Jika demikian, maka. data('key', 'value')metode tidak memperbarui nilai dalam cache jQuery tetapi karena alasan kinerja (saya kira DOM mutasi) DOM itu sendiri tidak diperbarui.
andyb
2
jadi jika Anda ingin memperbarui DOM, Anda harus melakukan .attr('key','value')terlepas dari apakah Anda melakukannya .data('key', 'value')atau tidak, kan? Itu tampak berlebihan bagi saya, dan saya mengalami kesulitan membayangkan skenario di mana Anda ingin menulis ke DOM yang di-cache, tetapi bukan DOM yang sebenarnya. Mungkin saya tidak mengerti cache jQuery; Jadi, akankah pengunjung melihat semua hal yang .data()dimodifikasi di layar mereka, atau tidak?
ahnbizcad
1
Jadi ini bukan hanya masalah kinerja; mereka tidak bisa dibandingkan. Mereka memiliki tujuan yang sama sekali berbeda, dan mereka mengubah "versi" DOM ​​yang berbeda. Jadi kembali ke pertanyaan: apa gunanya menggunakan .data () jika Anda harus melakukan .attr () untuk mengubah ACUTAL DOM? sepertinya berlebihan.
ahnbizcad
34

Saya mengalami masalah serius dengan

.data('property', value);

Itu tidak mengatur data-propertyatribut.

Mulai menggunakan jQuery's .attr():

Dapatkan nilai atribut untuk elemen pertama di set elemen yang cocok atau set satu atau lebih atribut untuk setiap elemen yang cocok.

.attr('property', value)

untuk mengatur nilai dan

.attr('property')

untuk mengambil nilai.

Sekarang berhasil!

Leniel Maccaferri
sumber
1
Bagi saya, saya bisa mengubah properti data dengan data () tapi saya perhatikan di alat pengembang itu tidak menunjukkan perubahan, jadi untuk alasan itu saya pergi dengan attr ()
drooh
8

Jawaban yang diterima @ andyb memiliki bug kecil. Lebih lanjut ke komentar saya pada posnya di atas ...

Untuk HTML ini:

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

Anda perlu mengakses atribut seperti ini:

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

tetapi metode datanya seperti ini:

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

Perbaikan di atas untuk metode .data () akan mencegah "tidak terdefinisi" dan nilai data akan diperbarui (sedangkan HTML tidak akan)

Titik atribut "data" adalah untuk mengikat (atau "tautan") nilai dengan elemen. Sangat mirip dengan onclick="alert('do_something')"atribut, yang mengikat aksi ke elemen ... teks tidak berguna Anda hanya ingin aksi bekerja ketika mereka mengklik elemen.

Setelah data atau tindakan terikat ke elemen, biasanya * tidak perlu memperbarui HTML, hanya data atau metode, karena itulah yang akan digunakan oleh aplikasi Anda (JavaScript). Dari segi kinerja, saya tidak mengerti mengapa Anda juga ingin memperbarui HTML, tidak ada yang melihat atribut html (kecuali di Firebug atau konsol lain).

Salah satu cara Anda mungkin ingin memikirkannya: HTML (beserta atribut) hanyalah teks. Data, fungsi, objek, dll yang digunakan oleh JavaScript ada di bidang yang terpisah. Hanya ketika JavaScript diperintahkan untuk melakukannya, itu akan membaca atau memperbarui teks HTML, tetapi semua data dan fungsi yang Anda buat dengan JavaScript bertindak sepenuhnya terpisah dari teks / atribut HTML yang Anda lihat di konsol Firebug (atau lainnya) Anda.

* Saya memberi penekanan pada biasanya karena jika Anda memiliki kasus di mana Anda perlu melestarikan dan mengekspor HTML (misalnya beberapa jenis format mikro / editor teks sadar data) di mana HTML akan memuat segar di halaman lain, maka mungkin Anda perlu memperbarui HTML terlalu.

Frank Forte
sumber
Terima kasih. Ini membantu, di antara semua jawaban lain dengan contoh yang salah! The datadalam attr('data-helptext'membuat perbedaan, di mana jawaban yang diterima dan yang dengan banyak orang yang tidak bekerja. +1
Aleks
6

Hal yang sama terjadi pada saya. Ternyata itu

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

memberi Anda objek yang tidak bisa ditulisi. Saya menyelesaikannya menggunakan:

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

Dan sejak saat dataitu , adalah objek JS standar yang dapat ditulis.

Nico
sumber
Bagaimana Anda menulisnya?
Bekerja untuk Hidup
Maaf Thom, saya tidak tahu apa maksud Anda ... Setelah melakukan $.extend..., Anda dapat menggunakan datasesuka Anda:, data.name = 'Nico'; data.questionSolved = true;dan console.log(data)akan menampilkan properti yang baru ditambahkan ini
Nico
3

Mengutip kutipan:

Atribut data ditarik pertama kali properti data diakses dan kemudian tidak lagi diakses atau bermutasi (semua nilai data kemudian disimpan secara internal di jQuery).

.data() - Dokumentasi jQuery

Perhatikan bahwa batasan ini (sangat aneh ) hanya ditahan untuk penggunaan .data().

Solusinya? Gunakan .attrsebagai gantinya.

Tentu saja, beberapa dari Anda mungkin merasa tidak nyaman karena tidak menggunakan metode khusus itu. Pertimbangkan skenario berikut:

  • 'Standar' diperbarui sehingga bagian data dari atribut khusus tidak lagi diperlukan / diganti

Akal sehat - Mengapa mereka mengubah atribut yang sudah ada seperti itu? Bayangkan saja classmulai diubah namanya menjadi grup dan iduntuk pengidentifikasi . Internet akan rusak.

Dan bahkan kemudian, Javascript sendiri memiliki kemampuan untuk memperbaikinya - Dan tentu saja, meskipun itu tidak sesuai dengan HTML, REGEX (Dan berbagai metode serupa) dengan cepat dapat mengubah nama atribut Anda ke 'standar' mitos-baru ini.

TL; DR

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

Seperti disebutkan, .data()metode ini tidak akan benar-benar menetapkan nilai data-atribut, juga tidak akan membaca nilai yang diperbarui jika data-atribut berubah.

Solusi saya adalah memperluas jQuery dengan .realData()metode yang benar-benar sesuai dengan nilai atribut saat ini:

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

CATATAN: Tentu saja Anda bisa menggunakan .attr(), tetapi dari pengalaman saya, sebagian besar pengembang (alias saya) membuat kesalahan dengan melihat .attr()dan .data()dipertukarkan, dan sering mengganti satu dengan yang lain tanpa berpikir. Ini mungkin bekerja sebagian besar waktu, tapi ini cara yang bagus untuk memperkenalkan bug, terutama ketika berhadapan dengan segala jenis pengikatan data dinamis. Jadi dengan menggunakan .realData(), saya bisa lebih eksplisit tentang perilaku yang dimaksud.

Yarin
sumber
0

Punya masalah yang sama. Karena Anda masih bisa mendapatkan data menggunakan metode .data (), Anda hanya perlu mencari cara untuk menulis ke elemen. Ini adalah metode pembantu yang saya gunakan. Seperti yang dikatakan kebanyakan orang, Anda harus menggunakan .attr. Saya memilikinya mengganti _ dengan - seperti yang saya tahu itu. Saya tidak mengetahui adanya karakter lain yang digantikannya ... namun saya belum merisetnya.

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: 5/1/2017

Saya menemukan masih ada contoh di mana Anda tidak bisa mendapatkan data yang benar menggunakan metode bawaan sehingga yang saya gunakan sekarang adalah sebagai berikut:

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