Невозможно установить атрибут данных с помощью jQuery Data() API

У меня есть следующее поле в представлении MVC:

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

В отдельном js файле я хочу установить атрибут data-helptext на строковое значение. Здесь мой код:

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

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

Вызов alert() отлично работает, он отображает текст "Старый текст" в диалоговом окне оповещения. Однако вызов установить атрибут data-helptext в "Тестирование 123" не работает. "Старый текст" по-прежнему является текущим значением атрибута.

Я неправильно использую вызов для данных()? Я просмотрел это в Интернете, и я не вижу, что я делаю неправильно.

Здесь разметка HTML:

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

Ответ 1

Он упоминается в .data() документации

Атрибуты данных вытаскиваются при первом доступе к свойствам данных, а затем больше не доступны или не изменяются (все значения данных затем сохраняются внутри jQuery)

Об этом также говорилось в Почему изменения в jQuery $.fn.data() не обновляют соответствующие атрибуты html 5 data- *?

Демо на моем первоначальном ответе ниже, похоже, больше не работает.

Обновленный ответ

Опять же, из .data() documentation

Обработка атрибутов встроенными тире была изменена в jQuery 1.6, чтобы соответствовать спецификации W3C HTML5.

Итак, для <div data-role="page"></div> верно следующее: $('div').data('role') === 'page'

Я уверен, что $('div').data('data-role') работал в прошлом, но, похоже, это не так. Я создал лучшую витрину, которая регистрируется в HTML, вместо того, чтобы открывать Консоль и добавила дополнительный пример атрибута multi-hyphen to camelCase data-attributes.

Обновлено демо (2015-07-25)

Также см. 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();

Старая демонстрация


Оригинальный ответ

Для этого HTML:

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

и этот JavaScript (с 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;
});

См. демонстрацию

Используя Chrome DevTools Консоль для проверки DOM, $('#foo').data('helptext', 'Testing 123'); не обновляет значение как отображается в консоли, но $('#foo').attr('data-helptext', 'Testing 123'); делает.

Ответ 2

У меня были серьезные проблемы с

.data('property', value);

Он не устанавливал атрибут data-property.

Начнется использование jQuery .attr():

Получить значение атрибута для первого элемента в наборе согласованные элементы или задать один или несколько атрибутов для каждого совпадающего элемент.

.attr('property', value)

чтобы установить значение и

.attr('property')

чтобы получить значение.

Теперь это просто работает!

Ответ 3

Принятый ответ @andyb имеет небольшую ошибку. В дополнение к моему комментарию к его сообщению выше...

Для этого HTML:

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

Вам нужно получить доступ к атрибуту следующим образом:

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

но метод данных выглядит следующим образом:

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

Исправленное выше для метода .data() предотвратит "undefined", и значение данных будет обновлено (пока HTML не будет)

Точкой атрибута "data" является привязка (или "ссылка" ) значения к элементу. Очень похоже на атрибут onclick="alert('do_something')", который связывает действие с элементом... текст бесполезен, вы просто хотите, чтобы действие работало, когда они нажимают на элемент.

Как только данные или действие привязаны к элементу, обычно нет необходимости обновлять HTML, только данные или метод, так как это будет использоваться вашим приложением (JavaScript). Производительность мудрая, я не понимаю, почему вы хотите также обновить HTML в любом случае, никто не видит атрибут html (кроме Firebug или других консолей).

Один из способов, который вы могли бы подумать об этом: HTML (наряду с атрибутами) - это просто текст. Данные, функции, объекты и т.д., Которые используются JavaScript, существуют на отдельной плоскости. Только тогда, когда JavaScript будет проинструктирован об этом, он будет читать или обновлять текст HTML, но все данные и функции, которые вы создаете с помощью JavaScript, действуют полностью отдельно от HTML-текста/атрибутов, которые вы видите в своей Firebug (или другой) консоли.

* Я обычно делаю акцент, потому что, если у вас есть случай, когда вам нужно сохранить и экспортировать HTML (например, какой-то текстовый редактор с микроформатом/данными), где HTML будет загружаться на другой странице, тогда, возможно, вам понадобится HTML также обновлен.

Ответ 4

Случилось то же самое со мной. Оказывается, что

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

предоставляет объект, не подлежащий записи. Я решил это, используя:

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

И с этого момента data был стандартным, записываемым JS-объектом.

Ответ 5

Чтобы процитировать цитату:

Атрибуты данных вытягиваются в первый раз, когда свойство данных доступ к ним и затем больше не доступны или не изменяются (все значения данных затем сохраняются внутри jQuery).

.data() - Документация jQuery

Обратите внимание, что это (нечетное) ограничение ограничивается только использованием .data().

Решение? Вместо этого используйте .attr.

Конечно, некоторые из вас могут чувствовать себя некомфортно, если не использовать выделенный метод. Рассмотрим следующий сценарий:

  • "Стандарт" обновляется, так что часть пользовательских атрибутов больше не требуется/заменяется

Здравый смысл - зачем им менять уже установленный атрибут? Представьте себе, что class начинает переименовываться в группу и id в идентификатор. Интернет сломается.

И даже тогда сам Javascript имеет возможность исправить это. И, конечно же, несмотря на это, позорная несовместимость с HTML, REGEX (и множество подобных методов) может быстро переименовать ваши атрибуты в этот новый мифический "стандарт".

TL; DR

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

Ответ 6

Была та же проблема. Поскольку вы все еще можете получать данные с использованием метода .data(), вам нужно только выяснить способ записи в элементы. Это вспомогательный метод, который я использую. Как и большинство людей, вы должны будете использовать .attr. Я его заменяю любым, поскольку я знаю, что это так. Я не знаю других символов, которые он заменяет... однако я не исследовал это.

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

РЕДАКТИРОВАТЬ: 5/1/2017

Я обнаружил, что все еще есть случаи, когда вы не могли получить правильные данные с помощью встроенных методов, поэтому теперь я использую следующее:

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