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

У меня есть следующее поле в представлении 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 значение «Testing 123» не работает. «Старый текст» по-прежнему является текущим значением атрибута.

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

Вот разметка HTML:

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

person Jason Evans    schedule 26.07.2011    source источник
comment
Код выглядит нормально. Нет проблем с этой демонстрацией. Какую версию jQuery вы используете?   -  person andyb    schedule 26.07.2011
comment
Я использую версию 1.5.1, которая поставляется с шаблоном проекта ASP NET MVC. Может быть, мне нужно обновить jQuery?   -  person Jason Evans    schedule 26.07.2011
comment
Ладно, тогда это не версия jQuery. Я подумал, что это может быть действительно старая версия. API data (), который вы используете, был добавлен в v1.2.3.   -  person andyb    schedule 26.07.2011
comment
Не могли бы вы добавить разметку? Вы используете собственный атрибут HTML5 data-?   -  person andyb    schedule 26.07.2011
comment
Как вы оцениваете ценность? jQuery не сохраняет значение обратно в DOM, хотя обновляет его правильно. Смотрите мой ответ ниже для теста и объяснения   -  person andyb    schedule 26.07.2011


Ответы (7)


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

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

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

Демонстрация моего исходного ответа ниже, похоже, больше не работает.

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

Опять же, из .data() документации

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

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

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

Обновленная демонстрация (2015-07-25)

Также см. Данные jQuery против 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 Console для проверки DOM, $('#foo').data('helptext', 'Testing 123'); не обновляет значение, как показано в консоли, но $('#foo').attr('data-helptext', 'Testing 123'); делает.

person andyb    schedule 26.07.2011
comment
Не уверен, что изменилось, но ваша демонстрация скрипки возвращает undefined в консоли Chrome - person manubkk; 04.12.2013
comment
Так в чем же смысл jQuery, позволяющего вводить второй аргумент? Чтобы обновить значение, хранящееся в кеше переменных js? - person ahnbizcad; 02.07.2014
comment
@gwho Я не уверен, что полностью понимаю ваш вопрос, но предполагаю, что вы имеете в виду исходный ответ от 2011 года с использованием jQuery 1.6.2. Если это так, то метод .data('key', 'value') действительно обновляет значение в кеше jQuery, но по соображениям производительности (я предполагаю, что мутация DOM) сама DOM не обновляется. - person andyb; 03.07.2014
comment
так что если вы хотите обновить DOM, вам нужно сделать .attr('key','value') независимо от того, сделали ли вы .data('key', 'value') или нет, верно? Мне это кажется избыточным, и мне сложно представить сценарий, в котором вы хотели бы писать в кэшированную DOM, но не в настоящую DOM. Может, я не понимаю кеш jQuery; Так будет ли посетитель видеть на своем экране все, что .data() изменяет, или нет? - person ahnbizcad; 03.07.2014
comment
Правильно, если вы действительно хотите обновить DOM, вам нужно что-то вроде .attr('key', 'value') или просто element.attributeName = value. Решение jQuery извлечь один раз из DOM, но это не мешает вам использовать другие методы, если вам действительно требуется обновление атрибутов DOM data-. Не забывайте, что речь идет о настраиваемых атрибутах HTML5, которые не предназначены для конкуренции с микроформатами. У вас все еще есть доступ к обновленному значению в JavaScript, где я ожидал бы его использовать. - person andyb; 03.07.2014
comment
Так что дело не только в производительности; их нельзя сравнивать. У них совершенно разные цели, и они меняют разные версии DOM. Итак, вернемся к вопросу: какой смысл использовать .data (), если вам нужно использовать .attr () для изменения ACUTAL DOM? кажется излишним. - person ahnbizcad; 15.07.2014
comment
Я всегда считал, что это делается исключительно из соображений производительности. этот тест связан с MDN Использование атрибутов data- * приводит к огромному снижению производительности при использовании setAttribute - person andyb; 16.07.2014
comment
кажется, это ошибка: console.log($('#foo').data('data-helptext'));, вероятно, должно быть: console.log($('#foo').data('helptext')); - person Frank Forte; 13.09.2014
comment
@Frankforte этот синтаксис был для старой версии jQuery. Я оставил свой исходный ответ, поскольку есть несколько способов получить атрибуты data-* с использованием разных версий jQuery. - person andyb; 13.09.2014
comment
Влияет ли это также на вновь добавленные элементы? Я клонировал строку таблицы, которая выглядит следующим образом: <tr data-id="5"></tr>, извлекла идентификатор, увеличила его, а затем применила $clone.data('id',new_index), а затем $tbody.append(clone), чтобы добавить новый TR. Но в новом TR все еще есть data-id="5". Почему это не сработает для вновь созданного элемента? - person Buttle Butkus; 25.09.2014
comment
Это очень расстраивает, потому что обработка jQuery этого И с использованием CSS3 attr(data-customdata) нарушает ожидаемую спецификацию HTML5, верно? Если единственными допустимыми настраиваемыми атрибутами являются data-, то этот допустимый вариант использования content: attr(data-xxx); не работает при использовании передовых методов настройки jQuery с jQuery.data(), потому что DOM - это OOS. - person JoeBrockhaus; 14.01.2015
comment
Это совершенно странно. У меня прямо противоположная ситуация. $('article#story').data('current', marker_data.id); работает, а $('article#story').attr('data-current', marker_data.id); ведет себя некорректно. : / - person Matt Komarnicki; 21.07.2015
comment
@slick, какую версию jQuery вы используете? Может что-то изменилось с тех пор, как я написал ответ - person andyb; 21.07.2015
comment
@andyb, jQuery v2.1.1 - person Matt Komarnicki; 21.07.2015
comment
@slick Я скоро обновлю свою демонстрацию, чтобы быть немного умнее, но я не вижу никаких проблем с более новым jQuery. Из вашего комментария неясно, что работает, а что нет. Установка через .attr не приведет к обновлению объекта jQuery. - person andyb; 21.07.2015
comment
@JoeBrockhaus, так что же делать, если ваш css зависит от изменения Dom? - person SuperUberDuper; 10.12.2015
comment
@SuperUberDuper Это было некоторое время назад, поэтому мой контекст сейчас ограничен, но я думаю, что ответ на этот вопрос вы должны знать, когда это так, а затем, помимо использования jQuery.data() (который не изменяет DOM), вы также должны обновите атрибут элемента DOM, чтобы content: attr(data-xxx); CSS подхватил его. - person JoeBrockhaus; 10.12.2015

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

.data('property', value);

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

Начат с помощью .attr() jQuery:

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

.attr('property', value)

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

.attr('property')

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

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

person Leniel Maccaferri    schedule 23.09.2014
comment
Что касается меня, я смог изменить свойство данных с помощью data (), но я заметил, что в инструментах разработчика он не показывает изменения, поэтому по этой причине я выбрал attr () - person drooh; 08.12.2016

В принятом ответе @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 не будет).

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

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

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

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

person Frank Forte    schedule 13.09.2014
comment
Спасибо. Это помогло, среди всех других ответов с неправильными примерами! data в attr('data-helptext' имеет значение, когда принятый ответ и ответы с большим количеством голосов не работают. +1 - person Aleks; 18.04.2016

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

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

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

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

И с тех пор data стал стандартным JS-объектом с возможностью записи.

person Nico    schedule 02.12.2013
comment
Как тогда в него писать? - person Works for a Living; 14.08.2014
comment
Извини, Том, я не знаю, что ты имеешь в виду ... Выполнив $.extend..., вы можете использовать data по своему усмотрению: data.name = 'Nico'; data.questionSolved = true;, и console.log(data) отобразит эти недавно добавленные свойства - person Nico; 14.08.2014

Процитирую цитату:

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

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

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

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

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

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

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

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

TL;DR

alert($(targetField).attr("data-helptext"));
person Super Cat    schedule 25.01.2015

Как уже упоминалось, метод .data() на самом деле не устанавливает значение атрибута data- и не считывает обновленные значения, если атрибут data- изменяется.

Мое решение заключалось в том, чтобы расширить jQuery методом .realData(), который фактически соответствует текущему значению атрибута:

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

ПРИМЕЧАНИЕ. Конечно, вы могли бы просто использовать .attr(), но по моему опыту, большинство разработчиков (также как и я) совершают ошибку, считая .attr() и .data() взаимозаменяемыми, и часто, не задумываясь, заменяют одно на другое. Это может работать большую часть времени, но это отличный способ внести ошибки, особенно при работе с любым типом динамической привязки данных. Таким образом, используя .realData(), я могу более четко определить предполагаемое поведение.

person Yarin    schedule 14.10.2018

Была такая же проблема. Поскольку вы все еще можете получать данные с помощью метода .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]);
    }
}

РЕДАКТИРОВАТЬ: 01.05.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;
};
person Matthew Pautzke    schedule 24.11.2015