wickywills
wickywills

Reputation: 4204

Using jQuery to get unknown data attributes and copy them to new element

I am trying to create a custom dropdown select style by converting a standard form select into a <li> list, however I need to add a few -data attributes to each <option> which then need to be copied over to the <li>.

The problem is that I do not always know what those data attributes will be called and therefore I would like a way of just copying any data attributes from the <option> tag onto the <li> tag.

My current code is as follows:

Original <option> tag...

<option data-somedata="something" data-else="something else" value="some value">Hello</option>

And the jQuery...

jQuery('.fancy-select .field option').each(function(){
  jQuery(this).parents('.fancy-select').find('ul').append('<li><a href="">' + jQuery(this).text() + '</a></li>')
});

Is there a way of copying all data attributes from my option tag to the <li> tags without specifying them by name?

Upvotes: 0

Views: 1284

Answers (3)

guest271314
guest271314

Reputation: 1

Try this (pattern)

html (e.g.)

<ul class="selections">
    <select>
        <option data-somedata="something" data-else="something else" value="some value">abc</option>
        <option data-somedata="something other" data-else="something else other" value="some value">def</option>
    </select>
</ul>

js

function optdata(selector, container, el) {
    $.each($(selector), function (index, value) {
        $(container).append(
        $(el).html("<a href=''>" + $(value).html() + "</a>")
        .data($(value).data()) 
        );
        return (index != $(value).size())
    });
};
optdata($("option"), $(".selections"), "<li>");

jsfiddle http://jsfiddle.net/guest271314/9NvJm/

Upvotes: 1

bjb568
bjb568

Reputation: 11498

Just clone the node:

jQuery('.fancy-select .field option').each(function(){
    this.parentNode.appendChild(this.cloneNode());
});

Since this is vanilla, and DOM manipulation instead of string manipulation, it will be much faster. And it's nice and simple too.

Fiddle

But you want it to be an <li>, not an <option>? You could change the outerHTML, but a faster way is:

jQuery('.fancy-select .field option').each(function() {
    var newNode = document.createElement('li');
    for (var i = this.attributes.length - 1; i--;) {
        newNode.attributes.setNamedItem(this.attributes[i].cloneNode());
    }
    this.parentNode.parentNode.appendChild(newNode);
});

Instead of cloning the entire node, then doing an expensive outerHTML replacement, it just copies attributes one by one!

Fiddle

Upvotes: 1

Jake
Jake

Reputation: 1026

It's been a while since I've used jQuery, but my first thought would be to look through the attributes looking for the "data-" ones.

Something like:

jQuery('.fancy-select .field option').each(function(){
    var $li = jQuery( '<li><a href="">' + jQuery(this).text() + '</a></li>' );
    jQuery.each( this.attributes, function ( item ) {
        if ( item.name.substring(0,6) === "data-" ) {
            $li.attr( item.name, item.value );
        }
    } );

    jQuery(this).parents('.fancy-select').find('ul').append( $li );
});

A quick Google reveals that data() might make this code much simplier if you are using a newer version of jQuery - https://api.jquery.com/jQuery.data/

jQuery('.fancy-select .field option').each(function(){
    var $li = jQuery( '<li><a href="">' + jQuery(this).text() + '</a></li>' );
    jQuery.each( jQuery(this).data(), function ( key, value ) {
        $li.data( key, value );
    } );

    jQuery(this).parents('.fancy-select').find('ul').append( $li );
});

Upvotes: 3

Related Questions