Неможливо встановити атрибут даних за допомогою 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" не працює. "Старий текст" все ще є поточним значенням атрибута.

Чи неправильно я використовую дзвінок до даних ()? Я подивився це в Інтернеті, і я не бачу, що я роблю не так.

Ось розмітка 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 (), який ви використовуєте, доданий у версії 1.2.3
andyb

Чи можете ви додати розмітку, будь ласка? Використовуєте спеціальний data-атрибут HTML5 ?
Андіб

Як ви спостерігаєте за цінністю? 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 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');


1
Не впевнений, що змінилося, але ваш скрипковий демонстратор повертається невизначеним у хромованій консолі
manubkk

Тож у чому сенс jQuery дозволяє вам поставити другий аргумент? Щоб оновити значення, збережене в кеші змінної js?
ahnbizcad

@gwho Я не впевнений, що я повністю розумію ваше запитання, але я припускаю, що ви посилаєтесь на оригінальну відповідь 2011 року, використовуючи jQuery 1.6.2. Якщо так, то data('key', 'value')Метод дійсно оновлює значення в кеші JQuery , але з причин продуктивності (я припускаю , що мутації DOM) сам DOM не оновлюється.
andyb

2
тому якщо ви хочете оновити DOM, вам потрібно буде зробити це .attr('key','value')незалежно від того, зробили ви це .data('key', 'value')чи ні, правда? Мені це здається зайвим, і у мене виникають проблеми уявити сценарій, коли ви хочете написати в кешований DOM, але не справжній DOM. Можливо, я не розумію кеш jQuery; Тож відвідувач побачив би всі зміни, що .data()змінюються на екрані, чи ні?
ahnbizcad

1
Тож це не лише питання продуктивності; їх не можна порівняти. Вони мають зовсім різні цілі, і вони змінюють різні "версії" DOM. Повернімося до питання: який сенс використовувати .data (), якщо вам доведеться зробити .attr (), щоб змінити АКТУАЛЬНИЙ ДОМ? здається зайвим.
ahnbizcad

34

У мене були серйозні проблеми

.data('property', value);

Це не було встановлення data-propertyатрибута.

Розпочато з використання jQuery .attr():

Отримайте значення атрибута для першого елемента в наборі відповідних елементів або встановіть один або кілька атрибутів для кожного відповідного елемента.

.attr('property', value)

встановити значення і

.attr('property')

щоб отримати значення.

Тепер це просто працює!


1
Для мене я зміг змінити властивість даних з даними (), але я помітив, що в інструментах для розробників це не показало змін, тому з цієї причини я пішов з attr ()
drooh

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 () запобігає "невизначеності", а значення даних буде оновлено (поки HTML не буде)

Суть атрибута "data" полягає в прив'язуванні (або "зв'язку") значення з елементом. Дуже схожий на onclick="alert('do_something')"атрибут, який пов'язує дію з елементом ... текст марний, ви просто хочете, щоб дія діяла, коли вони клацали елемент.

Після того, як дані або дії пов'язані з елементом, зазвичай * не потрібно оновлювати HTML, а лише дані або метод, оскільки саме це використовує ваша програма (JavaScript). Ефективність, я не розумію, чому ви хочете так само оновити HTML, ніхто не бачить атрибут html (за винятком Firebug чи інших консолей).

Один із способів, про який можна подумати: HTML (разом з атрибутами) - це лише текст. Дані, функції, об'єкти тощо, які використовуються JavaScript, існують в окремій площині. Тільки тоді, коли JavaScript буде доручено це робити, він буде читати або оновлювати текст HTML, але всі дані та функціональні можливості, які ви створюєте за допомогою JavaScript, діють повністю окремо від тексту HTML / атрибутів HTML, які ви бачите на своїй консолі Firebug (або іншої).

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


Дякую. Це допомогло серед усіх інших відповідей невірними прикладами! Значення " dataв" attr('data-helptext'робить різницю, коли прийнята відповідь та відповіді з багатьма голосами не працюють. +1
Алекс

6

Сталося те саме і зі мною. Виявляється, що

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

дає об’єкт, що не записується. Я вирішив це за допомогою:

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

І відтоді dataбув стандартним об'єктом JS, що записується.


Як ви тоді це пишете?
Працює для життя

Вибачте Тома, я не знаю, що ви маєте на увазі ... Після цього $.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]);
    }
}

РЕДАКТ: 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;
};
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.