ไม่สามารถตั้งค่าแอตทริบิวต์ข้อมูลโดยใช้ jQuery Data () API


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()โทรใช้งานได้ดีโดยจะแสดงข้อความ "Old Text" ในกล่องโต้ตอบการแจ้งเตือน อย่างไรก็ตามการเรียกเพื่อตั้งค่า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?
Jason Evans

ตกลงมันไม่ใช่เวอร์ชันของ jQuery แล้ว ฉันคิดว่ามันอาจจะเป็นเวอร์ชั่นเก่าจริงๆ data () API ที่คุณใช้ถูกเพิ่มใน v1.2.3
andyb

คุณช่วยเพิ่มมาร์กอัปได้ไหม คุณใช้data-แอตทริบิวต์HTML5 ที่กำหนดเองหรือไม่
andyb

สังเกตค่าเป็นอย่างไรบ้าง? jQuery ไม่คงค่ากลับไปที่ DOM แม้ว่าจะอัปเดตอย่างถูกต้องก็ตาม ดูคำตอบของฉันด้านล่างสำหรับการทดสอบและคำอธิบาย
andyb

คำตอบ:


239

มีการกล่าวถึงใน.data()เอกสารประกอบ

data- แอตทริบิวต์ถูกดึงในครั้งแรกที่มีการเข้าถึงคุณสมบัติข้อมูลจากนั้นจะไม่มีการเข้าถึงหรือกลายพันธุ์อีกต่อไป (จากนั้นค่าข้อมูลทั้งหมดจะถูกเก็บไว้ภายในใน jQuery)

นอกจากนี้ยังครอบคลุมถึงทำไมไม่เปลี่ยนเป็น jQuery $ .fn.data () อัปเดตแอตทริบิวต์ข้อมูล html 5 ที่สอดคล้องกัน

การสาธิตคำตอบเดิมของฉันด้านล่างดูเหมือนจะไม่ได้ผลอีกต่อไป

คำตอบที่อัปเดต

อีกครั้งจาก.data()เอกสาร

การรักษาแอตทริบิวต์ที่มีเครื่องหมายขีดกลางถูกเปลี่ยนใน jQuery 1.6 เพื่อให้สอดคล้องกับข้อกำหนด W3C HTML5

ดังนั้น<div data-role="page"></div>ต่อไปนี้เป็นความจริง$('div').data('role') === 'page'

ฉันค่อนข้างแน่ใจว่ามันใช้$('div').data('data-role')งานได้ในอดีต แต่ดูเหมือนจะไม่เป็นเช่นนั้นอีกต่อไป ฉันได้สร้างการแสดงที่ดีขึ้นซึ่งบันทึกเป็น HTML แทนที่จะต้องเปิดคอนโซลและเพิ่มตัวอย่างเพิ่มเติมของการแปลงขีดกลางหลายตัวให้กับ 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>

จาวาสคริปต์ (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

ฉันไม่แน่ใจว่าฉันเข้าใจคำถามของคุณอย่างสมบูรณ์ แต่ฉันคิดว่าคุณกำลังอ้างถึงคำตอบเดิมจากปี 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 () เพื่อเปลี่ยน ACUTAL DOM? ดูเหมือนซ้ำซ้อน
ahnbizcad

34

ฉันมีปัญหาร้ายแรงกับ

.data('property', value);

ไม่ได้ตั้งค่าdata-propertyแอตทริบิวต์

เริ่มใช้ jQuery's .attr():

รับค่าของแอตทริบิวต์สำหรับองค์ประกอบแรกในชุดขององค์ประกอบที่ตรงกันหรือตั้งค่าแอตทริบิวต์อย่างน้อยหนึ่งรายการสำหรับทุกองค์ประกอบที่ตรงกัน

.attr('property', value)

เพื่อตั้งค่าและ

.attr('property')

เพื่อดึงค่า

ตอนนี้ใช้งานได้แล้ว!


1
สำหรับฉันฉันสามารถเปลี่ยนคุณสมบัติข้อมูลด้วย data () แต่ฉันสังเกตเห็นในเครื่องมือของนักพัฒนามันไม่ได้แสดงการเปลี่ยนแปลงดังนั้นฉันจึงไปกับ 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" คือการผูก (หรือ "link") ค่ากับองค์ประกอบ คล้ายกับไฟล์onclick="alert('do_something')"แอตทริบิวต์ซึ่งเชื่อมโยงการกระทำกับองค์ประกอบ ... ข้อความไม่มีประโยชน์คุณเพียงแค่ต้องการให้การดำเนินการทำงานเมื่อคลิกองค์ประกอบนั้น

เมื่อข้อมูลหรือการกระทำถูกผูกไว้กับองค์ประกอบโดยปกติแล้วไม่จำเป็นต้อง*อัปเดต HTML เพียง แต่ข้อมูลหรือวิธีการเนื่องจากนั่นคือสิ่งที่แอปพลิเคชันของคุณ (JavaScript) จะใช้ ประสิทธิภาพที่ดีฉันไม่เห็นว่าทำไมคุณถึงต้องการอัปเดต HTML ด้วยไม่มีใครเห็นแอตทริบิวต์ html (ยกเว้นใน Firebug หรือคอนโซลอื่น ๆ )

วิธีหนึ่งที่คุณอาจต้องคิด: HTML (พร้อมกับแอตทริบิวต์) เป็นเพียงข้อความ ข้อมูลฟังก์ชันวัตถุและอื่น ๆ ที่ใช้โดย JavaScript มีอยู่บนระนาบแยกกัน เฉพาะเมื่อ JavaScript ได้รับคำสั่งให้ทำเท่านั้นมันจะอ่านหรืออัปเดตข้อความ HTML แต่ข้อมูลและฟังก์ชันทั้งหมดที่คุณสร้างด้วย JavaScript จะแยกออกจากข้อความ / แอตทริบิวต์ HTML ที่คุณเห็นในคอนโซล Firebug (หรืออื่น ๆ ) อย่างสิ้นเชิง

* ฉันให้ความสำคัญโดยทั่วไปเพราะหากคุณมีกรณีที่คุณต้องเก็บรักษาและส่งออก HTML (เช่นโปรแกรมแก้ไขข้อความรูปแบบไมโคร / ข้อมูลที่รับรู้) ซึ่ง HTML จะโหลดใหม่ในหน้าอื่นคุณอาจต้องอัปเดต HTML เกินไป.


ขอบคุณ. สิ่งนี้ช่วยได้ในบรรดาคำตอบอื่น ๆ ที่มีตัวอย่างที่ไม่ถูกต้อง! ช่องdataในattr('data-helptext'สร้างความแตกต่างโดยที่คำตอบที่ได้รับการยอมรับและคำตอบที่ได้รับการโหวตจำนวนมากไม่ทำงาน +1
Aleks

6

เกิดขึ้นเช่นเดียวกันกับฉัน ปรากฎว่า

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

ให้วัตถุที่ไม่สามารถเขียนได้ ฉันแก้ไขโดยใช้:

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

และจากนั้นเป็นต้นdataมาเป็นออบเจ็กต์ JS มาตรฐานที่เขียนได้


แล้วคุณจะเขียนถึงมันได้อย่างไร?
ทำงานเพื่อหาเลี้ยงชีพ

ขออภัย Thom ฉันไม่รู้ว่าคุณหมายถึงอะไร ... หลังจากทำเสร็จ$.extend...แล้วคุณสามารถใช้dataตามที่คุณต้องการ: data.name = 'Nico'; data.questionSolved = true;และconsole.log(data)จะแสดงคุณสมบัติที่เพิ่มใหม่นี้
Nico

3

หากต้องการเสนอราคา:

data- แอตทริบิวต์จะถูกดึงในครั้งแรกที่มีการเข้าถึงคุณสมบัติข้อมูลจากนั้นจะไม่มีการเข้าถึงหรือกลายพันธุ์อีกต่อไป (จากนั้นค่าข้อมูลทั้งหมดจะถูกเก็บไว้ภายใน jQuery)

.data() - เอกสาร jQuery

โปรดทราบว่าข้อ จำกัด( แปลกตรงไปตรงมา) นี้ถูกระงับไว้เฉพาะการใช้งาน.data()ถูกระงับเท่านั้นที่จะใช้

การแก้ไขปัญหา? ใช้.attrแทน

แน่นอนว่าคุณหลายคนอาจรู้สึกไม่สบายใจที่ไม่ได้ใช้วิธีนี้โดยเฉพาะ พิจารณาสถานการณ์ต่อไปนี้:

  • 'มาตรฐาน' ได้รับการอัปเดตเพื่อให้ไม่จำเป็นต้องใช้ส่วนข้อมูลของแอตทริบิวต์ที่กำหนดเองอีกต่อไป / ถูกแทนที่

สามัญสำนึก - ทำไมพวกเขาถึงเปลี่ยนแอตทริบิวต์ที่กำหนดไว้แล้วเช่นนั้น? แค่คิดclassเริ่มเปลี่ยนชื่อเป็นกลุ่มและidการระบุ อินเทอร์เน็ตจะพัง

และถึงอย่างนั้น Javascript เองก็มีความสามารถในการแก้ไขปัญหานี้ - และแน่นอนว่าแม้ว่าจะเข้ากันไม่ได้กับ HTML แต่ REGEX (และวิธีการที่คล้ายคลึงกันหลายวิธี) ก็สามารถเปลี่ยนชื่อแอตทริบิวต์ของคุณเป็น 'มาตรฐาน' ใหม่ในตำนานได้อย่างรวดเร็ว

TL; ดร

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

แก้ไข: 1/5/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;
};
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.