jQuery .data () не працює, але .attr () робить


107

Пробачте, що я не був більш конкретним щодо цього. У мене така дивна помилка. Після завантаження doc я замикаю певні елементи, які спочатку є data-itemname="", і встановлюю ці значення за допомогою .attr("data-itemname", "someValue").

Проблема: Коли я пізніше циклічно переймаю ці елементи, якщо це роблю elem.data().itemname, я отримую "", але якщо так elem.attr("data-itemname"), то отримую "someValue". Це так, як .data()геттер jQuery отримує лише ті елементи, які встановлені спочатку, щоб містити якесь значення, але якщо вони спочатку порожні, а пізніше встановлені, .data()вони не отримують значення згодом.

Я намагався відтворити цю помилку, але не зміг.

Редагувати

Я відтворив помилку! http://jsbin.com/ihuhep/edit#javascript,html,живіть

Також фрагменти зверху ...

JS:

var theaters = [
    { name: "theater A", theaterId: 5 },
    { name: "theater B", theaterId: 17 }
];

$("#theaters").html(
    $("#theaterTmpl").render(theaters)
);

// DOES NOT WORK - .data("name", "val") does NOT set the val
var theaterA = $("[data-theaterid='5']");
theaterA.find(".someLink").data("tofilllater", "theater5link"); // this does NOT set data-tofilllater
$(".someLink[data-tofilllater='theater5link']").html("changed link text"); // never gets changed

// WORKS - .attr("data-name", "val") DOES set val
var theaterB = $("[data-theaterid='17']");
theaterB.find(".someLink").attr("data-tofilllater", "theater17link"); // this does set data-tofilllater
$(".someLink[data-tofilllater='theater17link']").html("changed link text");

HTML:

<body>
    <div id="theaters"></div>
</body>

<script id="theaterTmpl" type="text/x-jquery-tmpl">
    <div class="theater" data-theaterid="{{=theaterId}}">
        <h2>{{=name}}</h2>
        <a href="#" class="someLink" data-tofilllater="">need to change this text</a>
    </div>
</script>

4
Спробуйте більше відтворити помилку :-)
dkamins

1
Хіба це не elem.data("itemname")НЕ elem.data().itemname?
Хоган

в той час як elem.data () .name name дозволить вам прочитати значення, НЕ БУДЕ Встановити значення. (Таким чином elem.data().itemname = somevalue;, не змінюються основні дані.)
Хоган

@dkamins - я відтворив помилку, будь ласка, перегляньте відредаговану версію.
Ян Девіс

Відповіді:


210

Я зіткнувся з подібною «помилкою» кілька днів тому під час роботи з .data()і .attr('data-name')атрибутами HTML5 даних.

Поведінка, яку ви описуєте, не є помилкою, а є дизайном.

.data()Виклик є особливим - він не тільки отримати HTML5 атрибути даних також спроби оцінити / синтаксичний аналіз атрибутів. Таким чином, з таким атрибутом, як, data-myjson='{"hello":"world"}'коли витягнути через .data(), повернеться час, Objectа пошук через .attr()поверне рядок. Дивіться приклад jsfiddle.

Оскільки .data()додаткова обробка jQuery зберігає результати оцінки атрибутів $.cache- врешті-решт, коли оцінюється атрибут даних, було б марно переоцінювати кожен .data()виклик, тим більше, що змінні даних можуть містити складні рядки JSON.

Я все це сказав, щоб сказати наступне: Після отримання атрибута через .data()будь-які зміни, внесені, .attr('data-myvar', '')не буде видно наступні .data()дзвінки. Перевірте це на jsfiddle.

Щоб уникнути цієї проблеми , не перемішуйте .dataта не дзвоніть .attr(). Використовуйте те чи інше.


позначаючи це як відповідь. перегляньте цей тест для всіх можливих сценаріїв з .data () vs. .attr (), що включає отримання та налаштування з використанням кожного та виведення довжини селекторів після їх встановлення, jsbin.com/acegef/edit# javascript, html, live
Ian Davis

9
Принаймні, це пояснює, очевидно, неінтуїтивну поведінку ... хоча це може спричинити невеликі головні болі при використанні сторонніх бібліотек, деякі з них використовують лише дані (), а інші змінюють фактичний атрибут.
Haroldo_OK

1
@leepowers, "Після отримання атрибуту через .data () будь-які зміни, внесені .attr ('data-myvar', ''), не будуть помічені при наступних викликах .data ()", якщо це дійсно є кешем ( $ .cache), то, здається, нічого хорошого! замість того, щоб сліпо покладатися на кеш, наступні виклики .data () могли зробити деякі основні перевірки (), наприклад, чи змінилося значення порожнього зараз або змінилася довжина рядка (відповідність кешу поточному значенню)
minhajul

1
Слід зазначити, що спроба встановити дані ('id', val) також не вдається, якщо значення не було отримано раніше ... чудова конструкція функції data () Jquery.
andreszs

3
Отже, кеш даних () зберігає мене годинами. Недарма, чому б я не змінив її значення, він все одно повертає те саме значення. Дякую за це
Ліннель Еммануель Нері

17

Це результат непорозуміння: dataНЕ є аксесуаром для data-*атрибутів . Це і більше, і менше.

dataє аксесуаром для кешу даних jQuery на елементі. Цей кеш ініціалізується з data-*атрибутів, якщо є присутні, але dataніколи не записує до атрибутів, а також зміна атрибуту не змінює кеш даних після ініціалізації:

const div = $("[data-example]");
console.log('div.data("example"):', div.data("example"));
console.log('div.attr("data-example"):', div.attr("data-example"));
console.log('Using div.data("example", "updated")');
div.data("example", "updated");
console.log('div.data("example"):', div.data("example"));
console.log('div.attr("data-example"):', div.attr("data-example"));
<div data-example="initial value"></div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

dataтакож масажує те, що він знаходить різними способами, вгадуючи типи даних, створюючи data("answer")елемент з data-answer="42"числом, а не рядком або навіть розбираючи речі як JSON, якщо вони виглядають як JSON:

console.log(typeof $("[data-answer]").data("answer"));
console.log(typeof $("[data-json]").data("json"));
console.log(typeof $("[data-str]").data("str"));
<div data-answer="42"></div>
<div data-json='{"answer":42}'></div>
<div data-str="example"></div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

Якщо ви хочете використовувати атрибути (як читання, так і їх встановлення), використовуйте attr, не data. attr є аксесуаром для атрибутів.


6

Це тому, що ім'я атрибута data-itemname. Ви не можете використовувати -в скороченому obj.attributeпозначенні (obj.data-itemname буде інтерпретуватися як "obj.data мінус назва елемента").


каже хто? чи можете ви надати посилання?
jahrichie

6

.attr("data-itemname", "someValue") змінює DOM.

.data("itemname", "someValue") змінює кеш jQuery.

Щоб це працювало в наступному Javascript і на додаток до CSS, ви повинні встановити обидва.

theaterA.find(".someLink").attr("data-itemname", "someValue");
theaterA.find(".someLink").data("itemname", "someValue");

4

Чому ви просто не використовуєте .data()всюди?

Ви також можете оголосити значення за замовчуванням вбудованими в HTML, що теж добре.

<span data-code="pony">text</span>

і

$("span").data("code") == "pony" // true

якщо ви хочете змінити це, ви просто зробите

$("span").data("code", "not-a-pony");

і видалити його цілком можна

$("span").removeData("code");

ви дійсно повинні намагатися уникати використання .attr("data-*"), я не знаю, чому ви все одно хочете це зробити.


s / should / must, використовуючи .attr('data-*', ...)не зробить дані видимими для.data()
ThiefMaster

Але це не робити з attr () так, як вам довелося б це зробити без jQuery? (з getAttribute tho)
powerbuoy

Якщо у вас немає jQuery, ви використовуєте getAttribute()і setAttribute()- так обидва способи отримають доступ до фактичних атрибутів, і він буде працювати знову. Або ви просто скористаєтесь dataSetвластивістю, яку надають сучасні браузери.
ThiefMaster

1
Не вибирайте такі елементи. Це жахливо неефективно, оскільки йому доведеться перебирати кожен елемент документа. Використовуйте classнатомість, оскільки у веб-переглядачів є вбудовані функції, щоб отримати елементи з певним класом.
ThiefMaster

1
але "555" - це дані, тому я повинен використовувати логіку data (). введення цих даних у назві класу змішує дані з презентацією. Я думаю, інший спосіб зробити це.
Ян Девіс

1

Ви повинні встановити дані, використовуючи .data('itemname', 'someValue');. Використання .attr()для встановлення атрибутів даних не працюватиме: http://jsfiddle.net/TentistMaster/YHsKx/

Однак ви можете надати вбудовані значення, використовуючи, наприклад, <div data-key="value">розмітку.


у jsfiddle, get працює після того, як ви виконаєте обидва набори. Таким чином, виконання attr ("data-itemname", "value") НЕ працює. Я використовую Chrome.
Іван Девіс

@Ian uh, ні. .data()виклик встановлює атрибут, в той час як .attr()виклик не робить нічого.
bevacqua

@IanDavis: Натисніть "встановити attr" і "get" дасть вам порожній об'єкт. Працює лише "встановити дані".
ThiefMaster

@Nico - це саме те, що я зробив: (1) натисніть кнопку "встановити attr", потім (2) натисніть кнопку "отримати". ось що сталося: воно мене насторожило, "{" test ":" meow "}". значить, .attr () встановлює атрибут. інакше попередження було б порожнім. Якщо ви дотримуєтесь цих точних кроків, чи отримуєте ви різні результати? Дякую.
Ян Девіс

1
@TentistMaster - в театріA у моєму наданому коді я взагалі не використовую .attr()лише .data(), а довжина селектора $(".someLink[data-tofilllater='theater5link']")- дорівнює нулю. тож як я маю користуватися .attr(): /
Ian Davis

0

Я бачу, що це спричинило певний поділ щодо того, як підходити до налаштування атрибутів даних.

Я занадто стикаюся з цією проблемою, і я виявив, що проблема видалася просто форматуванням атрибутів даних .

На мій досвід, вам слід уникати використання дефісів у змінній даних (назва змінної, що надходить після " data- ").

Це не спрацювало для мене:

[Розмітка]

<div class="list" id="myElement1" data-item-order="some-value"> .... </div>

[jQuery]

jQuery("#myElement1").data("item-order", "my-new-value");

Але наступне спрацювало чудово! :):

(Я використовую підкреслення замість дефісу, коли потрібно)

[Розмітка]

<div class="list" id="myElement1" data-item_order="some-value"> .... </div>

[jQuery]

jQuery("#myElement1").data("item_order", "my-new-value");

Я сподіваюся, що це допомагає. Привіт усім!

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.