Không thể đặt thuộc tính dữ liệu bằng API jQuery Data ()


131

Tôi đã có trường sau trên chế độ xem MVC:

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

Trong tệp js riêng biệt, tôi muốn đặt data-helptextthuộc tính thành giá trị chuỗi. Đây là mã của tôi:

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

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

Các alert() gọi hoạt động tốt, nó hiển thị văn bản "Văn bản cũ" trong hộp thoại cảnh báo. Tuy nhiên, lệnh gọi để đặt data-helptextthuộc tính thành "Kiểm tra 123" không hoạt động. "Văn bản cũ" vẫn là giá trị hiện tại của thuộc tính.

Tôi có đang sử dụng lệnh gọi dữ liệu () không chính xác không? Tôi đã tìm kiếm cái này trên web và tôi không thể thấy mình đang làm gì sai.

Đây là đánh dấu HTML:

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

Mã có vẻ ổn. Không có vấn đề trong bản demo này . Phiên bản jQuery nào bạn đang sử dụng?
andyb

Tôi đang sử dụng 1.5.1 đi kèm với mẫu dự án ASP NET MVC. Có thể là tôi cần cập nhật jQuery?
Jason Evans

OK, đó không phải là phiên bản của jQuery. Tôi đã nghĩ rằng nó có thể là một phiên bản thực sự cũ. API dữ liệu () mà bạn đang sử dụng đã được thêm vào v1.2.3
andyb

Bạn có thể thêm đánh dấu xin vui lòng? Bạn có đang sử dụng data-thuộc tính HTML5 tùy chỉnh không?
andyb

Làm thế nào bạn đang quan sát giá trị? jQuery không duy trì giá trị trở lại DOM, mặc dù nó cập nhật chính xác. Xem câu trả lời của tôi dưới đây để kiểm tra và giải thích
andyb

Câu trả lời:


239

Nó được đề cập trong .data()tài liệu

Các thuộc tính dữ liệu được kéo trong lần đầu tiên thuộc tính dữ liệu được truy cập và sau đó không còn được truy cập hoặc bị thay đổi (tất cả các giá trị dữ liệu sau đó được lưu trữ bên trong jQuery)

Điều này cũng được đề cập đến sao Không thay đổi đối với jQuery $ .fn.data () cập nhật các thuộc tính dữ liệu html * tương ứng?

Bản demo về câu trả lời ban đầu của tôi dưới đây dường như không còn hoạt động nữa.

Cập nhật câu trả lời

Một lần nữa, từ .data()tài liệu

Việc xử lý các thuộc tính bằng dấu gạch ngang được thay đổi trong jQuery 1.6 để phù hợp với đặc tả HTML5 của W3C.

Vì vậy đối với <div data-role="page"></div> sau đây là đúng$('div').data('role') === 'page'

Tôi khá chắc chắn rằng nó $('div').data('data-role')đã hoạt động trong quá khứ nhưng điều đó dường như không còn là vấn đề nữa. Tôi đã tạo một bản trình diễn tốt hơn để ghi nhật ký vào HTML thay vì phải mở Bảng điều khiển và thêm một ví dụ bổ sung về chuyển đổi thuộc tính dữ liệu đa dấu gạch nối sang camelCase .

Bản cập nhật cập nhật (2015-07-25)

Cũng xem 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();

Bản demo cũ hơn


Câu trả lời gốc

Đối với HTML này:

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

và JavaScript này (với 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;
});

Xem bản demo

Sử dụng Bảng điều khiển DevTools của Chrome để kiểm tra DOM, việc này không cập nhật giá trị như đã thấy trong Bảng điều khiển nhưng thực hiện.$('#foo').data('helptext', 'Testing 123'); $('#foo').attr('data-helptext', 'Testing 123');


1
Không chắc chắn điều gì đã thay đổi, nhưng bản demo fiddle của bạn trả về không xác định trong bảng điều khiển chrome
manubkk

Vậy thì điểm của jQuery cho phép bạn đưa vào một đối số thứ hai là gì? Để cập nhật giá trị được lưu trong bộ đệm biến js?
ahnbizcad

@gwho Tôi không chắc chắn tôi hoàn toàn hiểu câu hỏi của bạn, nhưng tôi giả sử bạn đang đề cập đến câu trả lời ban đầu từ năm 2011 bằng jQuery 1.6.2. Nếu vậy, thì. data('key', 'value')phương thức không cập nhật giá trị trong bộ đệm jQuery nhưng vì lý do hiệu năng (tôi đoán là đột biến DOM), bản thân DOM không được cập nhật.
andyb

2
Vì vậy, nếu bạn muốn cập nhật DOM, bạn cần phải thực hiện .attr('key','value')bất kể bạn có làm .data('key', 'value')hay không, phải không? Điều đó có vẻ dư thừa đối với tôi và tôi gặp khó khăn khi tưởng tượng một kịch bản mà bạn muốn ghi vào DOM được lưu trong bộ nhớ cache, nhưng không phải là DOM thực. Có lẽ tôi không hiểu bộ đệm jQuery; Vì vậy, một khách truy cập sẽ thấy tất cả những điều .data()sửa đổi trên màn hình của họ, hoặc họ sẽ không?
ahnbizcad

1
Vì vậy, nó không chỉ là vấn đề hiệu suất; họ không thể được so sánh. Chúng có các mục đích hoàn toàn khác nhau và chúng thay đổi các "phiên bản" khác nhau của DOM. Vì vậy, quay trở lại câu hỏi: điểm sử dụng .data () là gì nếu bạn phải làm .attr () để thay đổi DOM ACUTAL? có vẻ dư thừa.
ahnbizcad

34

Tôi đã có vấn đề nghiêm trọng với

.data('property', value);

Nó không được thiết lập data-property thuộc tính.

Bắt đầu sử dụng jQuery .attr():

Nhận giá trị của một thuộc tính cho phần tử đầu tiên trong tập hợp các phần tử được khớp hoặc đặt một hoặc nhiều thuộc tính cho mọi phần tử được khớp.

.attr('property', value)

để đặt giá trị và

.attr('property')

để lấy giá trị.

Bây giờ nó chỉ hoạt động!


1
Đối với tôi, tôi đã có thể thay đổi thuộc tính dữ liệu bằng dữ liệu () nhưng tôi đã nhận thấy trong các công cụ dành cho nhà phát triển, nó không hiển thị thay đổi, vì vậy, tôi đã đi với attr ()
drooh 7/12/2016

8

Câu trả lời được chấp nhận của @ andyb có một lỗi nhỏ. Thêm vào nhận xét của tôi về bài viết của mình ở trên ...

Đối với HTML này:

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

Bạn cần truy cập thuộc tính như thế này:

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

nhưng phương thức dữ liệu như thế này:

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

Khắc phục ở trên cho phương thức .data () sẽ ngăn "không xác định" và giá trị dữ liệu sẽ được cập nhật (trong khi HTML thì không)

Điểm của thuộc tính "dữ liệu" là liên kết (hoặc "liên kết") một giá trị với phần tử. Rất giống vớionclick="alert('do_something')" thuộc tính, liên kết một hành động với thành phần ... văn bản là vô dụng, bạn chỉ muốn hành động hoạt động khi họ nhấp vào yếu tố đó.

Khi dữ liệu hoặc hành động được liên kết với phần tử, thường * không cần cập nhật HTML, chỉ có dữ liệu hoặc phương thức, vì đó là những gì ứng dụng của bạn (JavaScript) sẽ sử dụng. Hiệu suất khôn ngoan, tôi không hiểu tại sao bạn cũng muốn cập nhật HTML, không ai thấy thuộc tính html (ngoại trừ trong Fireorms hoặc các bảng điều khiển khác).

Một cách bạn có thể muốn nghĩ về nó: HTML (cùng với các thuộc tính) chỉ là văn bản. Dữ liệu, hàm, đối tượng, v.v ... được JavaScript sử dụng tồn tại trên một mặt phẳng riêng. Chỉ khi JavaScript được hướng dẫn làm như vậy, nó mới đọc hoặc cập nhật văn bản HTML, nhưng tất cả dữ liệu và chức năng bạn tạo bằng JavaScript sẽ hoạt động hoàn toàn tách biệt với văn bản / thuộc tính HTML mà bạn thấy trong bảng điều khiển Fireorms (hoặc khác).

* Tôi thường nhấn mạnh vì nếu bạn gặp trường hợp cần bảo tồn và xuất HTML (ví dụ: một loại trình soạn thảo văn bản nhận dạng dữ liệu / định dạng vi mô), nơi HTML sẽ tải mới trên một trang khác, thì có thể bạn cần cập nhật HTML quá.


Cảm ơn. Điều này đã giúp, trong số tất cả các câu trả lời khác với các ví dụ không chính xác! Các datatrong attr('data-helptext'nên sự khác biệt, nơi mà các câu trả lời được chấp nhận và những người thân với nhiều phiếu không làm việc. +1
Aleks

6

Đã xảy ra tương tự với tôi. Hóa ra

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

cung cấp cho bạn một đối tượng không thể ghi. Tôi đã giải quyết nó bằng cách sử dụng:

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

Và từ đó trở đi, datalà một đối tượng JS tiêu chuẩn, có thể ghi.


Làm thế nào để bạn sau đó viết cho nó?
Hoạt động để kiếm sống

Xin lỗi Thom, tôi không biết ý của bạn là gì ... Sau khi làm $.extend..., bạn có thể sử dụng datanhư bạn muốn : data.name = 'Nico'; data.questionSolved = true;, và console.log(data)sẽ hiển thị các thuộc tính mới được thêm này
Nico

3

Để trích dẫn một trích dẫn:

Các thuộc tính dữ liệu được kéo trong lần đầu tiên thuộc tính dữ liệu được truy cập và sau đó không còn được truy cập hoặc bị thay đổi (tất cả các giá trị dữ liệu sau đó được lưu trữ bên trong jQuery).

.data() - Tài liệu jQuery

Lưu ý rằng giới hạn (thật kỳ quặc ) này chỉ được giữ lại để sử dụng .data().

Giải pháp? Sử dụng .attrthay thế.

Tất nhiên, một số bạn có thể cảm thấy không thoải mái khi không sử dụng phương pháp chuyên dụng. Hãy xem xét kịch bản sau đây:

  • 'Tiêu chuẩn' được cập nhật để phần dữ liệu của các thuộc tính tùy chỉnh không còn cần thiết / được thay thế

Tâm lý chung - Tại sao họ sẽ thay đổi một thuộc tính đã được thiết lập như vậy? Chỉ cần tưởng tượng classbắt đầu đổi tên thành nhómidđể nhận dạng . Internet sẽ phá vỡ.

Và ngay cả khi đó, bản thân Javascript cũng có khả năng khắc phục điều này - Và tất nhiên, mặc dù nó không tương thích với HTML, REGEX (Và một loạt các phương pháp tương tự) có thể nhanh chóng đổi tên các thuộc tính của bạn thành 'tiêu chuẩn' huyền thoại mới này.

TL; DR

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

1

Như đã đề cập, .data()phương thức sẽ không thực sự đặt giá trị của data-thuộc tính, và cũng sẽ không đọc các giá trị được cập nhật nếu data-thuộc tính thay đổi.

Giải pháp của tôi là mở rộng jQuery bằng một .realData()phương thức thực sự tương ứng với giá trị hiện tại của thuộc tính:

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

LƯU Ý: Chắc chắn bạn chỉ có thể sử dụng .attr(), nhưng từ kinh nghiệm của tôi, hầu hết các nhà phát triển (còn gọi là tôi) đều mắc lỗi khi xem .attr().data()thay thế cho nhau, và thường thay thế cái này cho cái khác mà không cần suy nghĩ. Nó có thể hoạt động hầu hết thời gian, nhưng đó là một cách tuyệt vời để giới thiệu các lỗi, đặc biệt là khi xử lý bất kỳ loại ràng buộc dữ liệu động nào. Vì vậy, bằng cách sử dụng .realData(), tôi có thể rõ ràng hơn về hành vi dự định.


0

Có cùng một vấn đề. Vì bạn vẫn có thể lấy dữ liệu bằng phương thức .data (), bạn chỉ phải tìm ra cách ghi vào các phần tử. Đây là phương pháp trợ giúp tôi sử dụng. Giống như hầu hết mọi người đã nói, bạn sẽ phải sử dụng .attr. Tôi có nó thay thế bất kỳ _ với - như tôi biết nó làm điều đó. Tôi không biết về bất kỳ nhân vật nào khác mà nó thay thế ... tuy nhiên tôi chưa nghiên cứu về điều đó.

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

Tôi thấy vẫn còn những trường hợp bạn không thể lấy được dữ liệu chính xác bằng các phương thức tích hợp sẵn, vì vậy những gì tôi sử dụng bây giờ là như sau:

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;
};
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.