How to copy all the attributes of one element and apply them to another?
Asked Answered
H

12

82

How do I copy the attributes of one element to another element?

HTML

<select id="foo" class="bar baz" style="display:block" width="100" data-foo="bar">...</select>

<div>No attributes yet</div>

JavaScript

var $div = $('div');
var $select = $('select');

//now copy the attributes from $select to $div
Hankins answered 19/7, 2011 at 20:1 Comment(5)
Are you sure you want to copy id?Nimrod
If it is going to copy the id attribute you will have a duplicated id.Kacykaczer
Perhaps you could explain why you need to this? There's likely a better solution.Mystique
Don't worry, I will either not copy the ID attrbute or remove the duplicate ID attribute.Hankins
Because I don't want to forget an attribute if I copy each one by hand. Also, I didn't know how to do this, so I wanted to ask so I could learn how to do it in the future.Hankins
N
89

You can use the native Node#attributes property: http://jsfiddle.net/SDWHN/16/.

var $select = $("select");
var $div = $("div");

var attributes = $select.prop("attributes");

// loop through <select> attributes and apply them on <div>
$.each(attributes, function() {
    $div.attr(this.name, this.value);
});

alert($div.data("foo"));
Nimrod answered 19/7, 2011 at 20:12 Comment(4)
As a note: attributes array is far from compatible. Yes, it is core, but IE in earlier version treats 'core' properties as it pleases. I use "hackish", but as paradox more compliant way taken from forum.jquery.com/topic/… - make node a string representation, change it's tag with regexp and convert back to node. Then I can re-attach data and events. IE version threw errors on copying some of the attributes (ex 'implementation' attribute - did you know it's attached to all tags?)Run
Kudos for prepending your variables with '$' when they contain references to jQuery objects. I started this trend in my current company... it makes it MUCH easier to read the code quickly!Septuor
Would like to ask a side question related to this. I tried $something.prop('attributes') and it give an array with attributes. One of them is crossorigin for an image. I tried $item.prop('crossorigin') which is undefined but if I try $item.prop('src'), it give result. And then I tried $item.attr('crossorigin') which give the value. What is the difference of .attr() and .prop()? Why is the above situation somewhat different? Thanks in advance.Dygall
@simongcc .prop gets a property from the underlying native Node object representing the DOM of the element. .attr gets the value of a HTML attribute as defined programmatically or via markup.Charie
T
36

ES6 syntax one liner:

function cloneAttributes(target, source) {
  [...source.attributes].forEach( attr => { target.setAttribute(attr.nodeName ,attr.nodeValue) })
}

And as noted in the first comment - you would probably don't want to copy the source id attribute... so this one will save it as a 'data-id' attribute in case you need a reference.

function cloneAttributes(target, source) {
  [...source.attributes].forEach( attr => { target.setAttribute(attr.nodeName === "id" ? 'data-id' : attr.nodeName ,attr.nodeValue) })
}
Trutko answered 5/6, 2018 at 8:21 Comment(4)
best answer so far. It's 2020.Stratiform
This is a better solution than the accepted answer. It's clean and can easily be used interchangeably between vanilla JS and jQuery.Piscatory
nodeName, nodeValue are deprecated now developer.mozilla.org/ru/docs/Web/API/AttrRegalado
What I did was use attr.name and attr.value instead of attr.nodeName and attr.nodeValue respectively. It still works as expected.Advanced
S
14

Pretty Simple

function cloneAttributes(element, sourceNode) {
  let attr;
  let attributes = Array.prototype.slice.call(sourceNode.attributes);
  while(attr = attributes.pop()) {
    element.setAttribute(attr.nodeName, attr.nodeValue);
  }
}
Signesignet answered 12/12, 2015 at 8:20 Comment(3)
Also note that this method does not copy any unnecessary primitive types. It only clones each attribute.Signesignet
Is there a reason why you use Array#slice and while instead of just Array#forEach?Facesaving
Probably for dead browsers compatibility.Eme
K
11

A working solution on jsfiddle

EDIT

Updated jsfiddler

Javascript

$(function(){
    var destination = $('#adiv').eq(0);
    var source = $('#bdiv')[0];

    for (i = 0; i < source.attributes.length; i++)
    {
        var a = source.attributes[i];
        destination.attr(a.name, a.value);
    }
});

HTML

<div id="adiv" class="aclass">A class</div>
<div id="bdiv" class="bclass">B class</div>

That's copying #bdiv attributes to #adiv.

Kacykaczer answered 19/7, 2011 at 20:16 Comment(3)
You should post at least the important part of your code here, if for no other reason than if jsfiddle ever disappears your answer remains.Arsine
@kingjiv, Thank's for advising.Kacykaczer
This seems to have a problem in IE (8) where it finds far too many properties (100+) and jQuery throws a member not found exception when trying to set the attribute.Burghley
P
3

We could also try extending the jQuery prototype ($.fn) object to provide a new method that can be chained to the jQuery() function.

Here's an extension of @pimvdb's solution to provide a function that copies all attributes

The usage would be like so:

 $(destinationElement).copyAllAttributes(sourceElement);

The extension function can be defined like so:

(function ($) {

    // Define the function here
    $.fn.copyAllAttributes = function(sourceElement) {

        // 'that' contains a pointer to the destination element
        var that = this;

        // Place holder for all attributes
        var allAttributes = ($(sourceElement) && $(sourceElement).length > 0) ?
            $(sourceElement).prop("attributes") : null;

        // Iterate through attributes and add    
        if (allAttributes && $(that) && $(that).length == 1) {
            $.each(allAttributes, function() {
                // Ensure that class names are not copied but rather added
                if (this.name == "class") {
                    $(that).addClass(this.value);
                } else {
                    that.attr(this.name, this.value);
                }

            });
        }

        return that;
    }; 

})(jQuery);

An Example is available at http://jsfiddle.net/roeburg/Z8x8x/

Hope this helps.

Prebendary answered 8/7, 2014 at 8:5 Comment(1)
Your code has unnecessary duplicate jQuery wrappers/initializations. See my changes: jsfiddle.net/5eLdcya6Pope
G
3

You can try this:

function copyAttributes(from, to)
{
  $($(from)[0].attributes).
    each(function(){$(to).attr(this.nodeName, this.nodeValue);});

  return $(to);
};

The return statement lets you write things like:

copyAttributes(some_element, $('<div></div>')).append(...) ...

Hope this helps.

Gamogenesis answered 12/8, 2016 at 8:38 Comment(0)
P
2

A non-jquery solution:

function copy(element){
    var clone = document.createElement(element.nodeName);
    for(key in element){
        clone.setAttribute(key,element[key]);
    }
    return clone;
}

It copies methods and other stuff you probably don't need, but hopefully you don't mind. This code is small and simple.

Palsy answered 14/11, 2014 at 4:22 Comment(0)
G
2

I'm facing same problem and after invested lots of time and effort i am creating thisclone textarea into editable div with same attribute

select.getAttributeNames().forEach(attrName => {
  $(div).attr(attrName, inputData.getAttribute(attrName));
});
Griceldagrid answered 19/9, 2018 at 12:38 Comment(0)
W
1

A very straight to the point solution would be make something like this:

const _$ = domQuery => document.querySelector(domQuery)
let div1 = _$('#div-1')
let div2 = _$('#div-2')

for(attr of div1.attributes) {
  div2.setAttribute(attr.name, attr.value);
}
.my-div {
height: 100px;
width: 100px;
}
<h1>div-1</h1>
<div atribute-test="test" class="my-div" style="background: red" id="div-1"></div>
<h1>div-2</h1>
<div id="div-2"></div>
What answered 15/5, 2021 at 12:33 Comment(0)
R
0

Since Firefox 22, Node.attributes is no longer supported (not implemented by other browsers and removed from the spec). It is only supported on Element (Element.attributes).

Roscoe answered 30/9, 2013 at 18:34 Comment(1)
This doesn't matter at all for OP, he doesn't talk about text or other nodes.Amazonite
P
-1

Javascript solution

Copy the attributes of old element to the new element

const $oldElem = document.querySelector('.old')
const $newElem = document.createElement('div')

Array.from($oldElem.attributes).map(a => {
  $newElem.setAttribute(a.name, a.value)
})

Replace the old element with the new element, if required

$oldElem.parentNode.replaceChild($newElem, $oldElem)
Pierides answered 6/8, 2018 at 1:35 Comment(0)
B
-2
$("div").addClass($('#foo').attr('class'));
Bi answered 19/7, 2011 at 20:6 Comment(2)
my mistake, i thought you wanted to copy the css.Bi
Although it was a mistake, it's exactly what I was googling for. So, thanks! ;)Jauch

© 2022 - 2024 — McMap. All rights reserved.