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

131

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

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

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

<input data-helptext="Old Text" id="Course_Title" name="Course.Title" type="text" value="" />
Джейсон Эванс
источник
Код выглядит нормально. В этой демонстрации проблем нет . Какую версию jQuery вы используете?
Andyb
Я использую версию 1.5.1, которая поставляется с шаблоном проекта ASP NET MVC. Может быть, мне нужно обновить jQuery?
Джейсон Эванс
Хорошо, тогда это не версия jQuery. Я подумал, что это может быть действительно старая версия. API data (), который вы используете, был добавлен в v1.2.3
andyb
Не могли бы вы добавить разметку? Вы используете собственный data-атрибут HTML5 ?
Andyb
Как вы оцениваете ценность? jQuery не сохраняет значение обратно в DOM, хотя обновляет его правильно. Смотрите мой ответ ниже для теста и объяснения
Andyb

Ответы:

239

Это упоминается в .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 .

Обновленная демоверсия (25.07.2015)

Также см. Данные jQuery 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');делает.

andyb
источник
1
Не уверен, что изменилось, но ваша демонстрация скрипки возвращает undefined в консоли Chrome
manubkk
Так в чем же смысл jQuery, позволяющего вводить второй аргумент? Чтобы обновить значение, хранящееся в кеше переменных js?
ahnbizcad 02
@gwho Я не уверен, что полностью понимаю ваш вопрос, но предполагаю, что вы имеете в виду исходный ответ 2011 года с использованием jQuery 1.6.2. Если да, то файл. data('key', 'value')Метод действительно обновляет значение в кэше JQuery , но по причинам производительности (я предполагаю , что мутации DOM) сам DOM не обновляется.
Andyb 02
2
так что если вы хотите обновить DOM, вам нужно будет это сделать .attr('key','value')независимо от того, сделали вы это .data('key', 'value')или нет, верно? Мне это кажется избыточным, и мне сложно представить сценарий, в котором вы хотели бы писать в кэшированную DOM, но не в настоящую DOM. Может, я не понимаю кеш jQuery; Так будет ли посетитель видеть все, что .data()изменяется на своем экране, или нет?
ahnbizcad
1
Так что дело не только в производительности; их нельзя сравнивать. У них совершенно разные цели, и они меняют разные «версии» DOM. Итак, вернемся к вопросу: какой смысл использовать .data (), если вам нужно использовать .attr () для изменения ACUTAL DOM? кажется излишним.
ahnbizcad
34

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

.data('property', value);

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

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

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

.attr('property', value)

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

.attr('property')

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

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

Лениэль Маккаферри
источник
1
Что касается меня, я смог изменить свойство данных с помощью data (), но я заметил в инструментах разработчика, что оно не показывает изменения, поэтому по этой причине я
выбрал
8

В принятом ответе @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 слишком.

Фрэнк Форте
источник
Спасибо. Это помогло, среди всех других ответов с неправильными примерами! dataВ attr('data-helptext'решаюшее, где общепринятый ответ и те , с большим количеством голосов , которые не работают. +1
Алекс
6

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

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

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

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

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

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

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

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

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

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

Решение? использование.attr вместо этого.

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

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

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

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

TL; DR

alert($(targetField).attr("data-helptext"));
Супер Кот
источник
1

Как уже упоминалось, .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(), я могу более четко определить предполагаемое поведение.

Ярина
источник
0

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