简体   繁体   中英

JQuery data attribute selector undefined

I'm having trouble with data attributes in some basic html and javascript. I have several links throughout a page that dynamically insert a map and a 'close' link to get rid of the map.

The links are all similar to:

<a class="maplocation" href="#" data-coords="4645/234234" data-zoom="9">Link text<span class="mapslideicon"></span></a>

And the javascript on clicking these links is:

$("a.maplocation").click(function() {
    if ($(this).data("mapopen") == true) {
        // Map already clicked and open, do nothing
    } else {
        var timeStamp = $.now();
        var mapID = "m_"+timeStamp;
        var mapCloseID = "c_"+timeStamp;
        var anchorID = "a_"+timeStamp;
        var mapClass = 'widemap';
        var mapDiv = $("<div class='"+mapClass+"' id='"+mapID+"'>&nbsp;</div><a href='#' id='"+mapCloseID+"' class='maplocationclose'>close</a>");
            mapDiv.insertAfter($(this).parent());
        // Set a data attribute on the link to let it know a map is open
        $(this).data( "mapopen", true );
        // Set a data attribute on the link so that we can reference it from the close button
        $(this).data( "anchorid", anchorID );
    }
    return false;
});

This creates a div for a map, places a data attribute on the original anchor to say that the map is open and also creates an anchor for closing the map.

When the close map anchor is clicked it executes the following:

$('body').on('click', 'a.maplocationclose', function(){ // delegated.
        var id = $(this).attr('id');
        idNo = id.split("_");
        var assocMapID = "m_"+idNo[1];
        var assocAnchorID = "a_"+idNo[1];
        $("#"+id).remove();
        $("#"+assocMapID).slideUp( 300, function() {
            $("#"+assocMapID).remove();
        });
    // Set a data elemt on the original map link that let's us know the map is closed again
    $('.maplocation[anchorid="'+assocAnchorID+'"]').data( "mapopen", false );
    return false;
});

This all works but I'm having difficulty in accessing the data-attribute from the close anchor. It references fine from the original link, as I intended, and sets the mapped attribute as true and reads it as true. However, when I set it to false in the close anchor it cannot find it and it's never set.

I've run a test (from inside the maplocationclose function) to see if I can find any data attributes from the anchor, such as:

console.log("Zoom Attr is: " + $('a.maplocation[anchorid="'+assocAnchorID+'"]').data('zoom'));

And they're returning 'undefined'.

Attaching data using .data() does not add/alter any data-* attributes, hence your attribute selector won't match anything.

You can use filter instead though:

$('.maplocation').filter(function(){
    return $(this).data('anchorid') == assocAnchorID;
}).data( "mapopen", false );

Just to expand on the comments following @Georges answer.

Your code that is causing issues:

$('.maplocation[anchorid="'+assocAnchorID+'"]').data( "mapopen", false );

Now, first of all the syntax for this selector is wrong. Even if you have a data attribute named anchorid on an element, that is not how you would retrieve it. You should include the data- part; data-anchorid .

Check the below example, and the console output, to understand why it is failing:

<div class="maplocation" data-anchorid="25" data-test="works">...</div>  

var x = $('.maplocation[anchorid="25"]');
var y = $('.maplocation[data-anchorid="25"]');
console.log('Length of x: ' + x.length) //This is 0, because element x does not exist
console.log('Length of y: ' + y.length) //1
console.log('Value of x: ' + x.data('test')) //This is undefined because element x does not exist
console.log('Value of y: ' + y.data('test')) //works

But, that doesn't solve the issue, since you have no attribute on the actual element you can't use that selector either. data() is not writing to the element, like attr() does, but instead it only adds the keys/values to the jQuery internal collection/cache.

jQuery docs on data() :

Store arbitrary data associated with the matched elements or return the value at the named data store for the first element in the set of matched elements.

jQuery docs on attr() :

Get the value of an attribute for the first element in the set of matched elements or set one or more attributes for every matched element.

See this for an illustration:

$('.maplocation').data('mydata','myvalue'); //Only added to jQuery collection/internal cache, not DOM/element
console.log($('.maplocation[data-mydata="myvalue"]').data('test')) //undefined
$('.maplocation').attr('data-mydata','myvalue'); //Added to DOM/element
console.log($('.maplocation[data-mydata="myvalue"]').attr('data-test')) //works

Solutions
So, the solution provided by George will work since it will get a collection of all elements with .maplocation and then filter that to only return the one that has a .data('anchorid') == assocAnchorID .

Other options:

  • You can use attr() instead of data() for setting/getting. Everything will be treated as strings, so you'll have to modify the code accordingly, and remember to include 'data-' when using it (example: data('test') should be attr('data-test') ). Example:

     $('.maplocation[data-anchorid="'+assocAnchorID+'"]').attr( "data-mapopen", "false" ); 
  • You can use another selector to get the element, then use data() as normal. This is just an example as I don't know if closest will work with your structure:

     $(this).closest('.maplocation').data( "mapopen", false ); 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM