135

How can I set multiple attributes at once with JavaScript? Unfortunately, I'm not able to use a framework like jQuery on this project. Here is what I have now:

var elem = document.createElement("img");

elem.setAttribute("src", "http://example.com/something.jpeg");
elem.setAttribute("height", "100%");
elem.setAttribute("width", "100%");
2
  • 4
    Answer from @Quantastical using Object.assign() is worth a look for those that don't want to create a helper function - works for "all enumerable and own properties". Commented Sep 18, 2018 at 20:30
  • 7
    I scrolled through all of the answers, hoping that in 7 years since this question was posted that there would be some sort of ES7 update, making it so we don't have to write our own function like @Ariel's answer Commented Oct 24, 2019 at 17:28

17 Answers 17

166

You could make a helper function:

function setAttributes(el, attrs) {
  for(var key in attrs) {
    el.setAttribute(key, attrs[key]);
  }
}

Call it like this:

setAttributes(elem, {"src": "http://example.com/something.jpeg", "height": "100%", ...});
Sign up to request clarification or add additional context in comments.

7 Comments

well it's not at once also, so there will be no affect over performance.
This is not what he asked. We need to know how to improve the performance
@jbartolome - The word "performance" is not mentioned once in the question. I don't know where you got that notion from. The question appears to be looking for a way to not have to manually call elem.setAttribute() multiple times.
I am not sure what the question really wants. A good possible desired outcome is to call attributeChangedCallback "only once". If I need to call a function that depends on two attributes, usually attributeChangedCallback is called twice, one for each attribute change. Accessing this.getAttribute('your-attr') for both attributes and exiting if one of them is still empty is a first solution BUT it does not handle the case where only one attribute is set, and the other one already has a previous value. But god helps this is not the question actually objective. Not easy!
As of ECMAScript 8, you can use Object.entries() which avoids one having to look up each value in the original object. This allows one to write the function as: function setAttributes(el, attrs) { Object.entries(attrs).forEach(([key, value]) => el.setAttribute(key, value)); }
|
62

You might be able to use Object.assign(...) to apply your properties to the created element. Although some "properties (elem.height etc.) are read-only, i.e. accessors with only a getter (undefined setter)."

Keep in mind that height and width attributes are defined in pixels, not percents. You'll have to use CSS to make it fluid.

var elem = document.createElement('img')
Object.assign(elem, {
  className: 'my-image-class',
  src: 'https://dummyimage.com/320x240/ccc/fff.jpg',
  height: 120, // pixels
  width: 160, // pixels
  onclick: function () {
    alert('Clicked!')
  }
})
document.body.appendChild(elem)

// One-liner:
// document.body.appendChild(Object.assign(document.createElement(...), {...}))
.my-image-class {
  height: 100%;
  width: 100%;
  border: solid 5px transparent;
  box-sizing: border-box
}

.my-image-class:hover {
  cursor: pointer;
  border-color: red
}

body { margin:0 }

7 Comments

The properties, elem.height etc., are read-only, so this fails. I looked at the descriptors, and they are accessors with only a getter (undefined setter).
@lukeuser Thank you for the comment. I did not know that those properties were read-only.
To your question about "couldn't you just..." I asked this probably when you actually couldn't just.
@JPSilvashy I didn't intend for my "couldn't you just" to come across as belittling or to show a sign of superiority. Sorry if it did. I honestly wasn't sure if this would've been a suitable answer as I'm no JavaScript ninja, so I was hoping others like lukeuser might chime in to help solidify the logic.
See comments for additional details. Comments can be removed at any time. Anything important should be added to the post, not referred to from the post.
|
17

2023 Update Don't use this as an extension to Element.prototype. In 2012, it was debatable practice. In 2023, the debate is settled: it's not the way to go about things. Manipulating the prototype of library-external classes has risks that are difficult or impossible to mitigate; this is an ugly tool. I tried to note that, but was apparently not emphatic enough.

However, you can read the internal approach of the method and write it as a function, it would work the same. I might use something like this:

const setAttributes = (el, attrs) =>
  Object.keys(attrs)
    .filter(key => el[key] !== undefined)
    .forEach(key =>
      typeof attrs[key] === 'object'
        ? Object.keys(attrs[key])
            .forEach(innerKey => el[key][innerKey] = attrs[key][innerKey])
        : el[key] = attrs[key]
    );

http://jsfiddle.net/uL8tm603/46/

Original 2012 answer follows


If you wanted a framework-esq syntax (Note: IE 8+ support only), you could extend the Element prototype and add your own setAttributes function:

Element.prototype.setAttributes = function (attrs) {
    for (var idx in attrs) {
        if ((idx === 'styles' || idx === 'style') && typeof attrs[idx] === 'object') {
            for (var prop in attrs[idx]){this.style[prop] = attrs[idx][prop];}
        } else if (idx === 'html') {
            this.innerHTML = attrs[idx];
        } else {
            this.setAttribute(idx, attrs[idx]);
        }
    }
};

This lets you use syntax like this:

var d = document.createElement('div');
d.setAttributes({
    'id':'my_div',
    'class':'my_class',
    'styles':{
        'backgroundColor':'blue',
        'color':'red'
    },
    'html':'lol'
});

Try it: http://jsfiddle.net/ywrXX/1/

If you don't like extending a host object (some are opposed) or need to support IE7-, just use it as a function

Note that setAttribute will not work for style in IE, or event handlers (you shouldn't anyway). The code above handles style, but not events.

Documentation

14 Comments

more simplified recursive version: jsfiddle includes an IE shim
For the record, many developers consider it to be a poor and risky practice to extend built-in prototypes with non-standard methods.
@ChrisBaker - Yeah, I know you did, but your answer suggests and shows doing it. Many (including me) think that's a bad practice.
Don't extend objects you don't own. It's bad practice and you will be bitten.
"Entire frameworks like Prototype were built" yes, and that doesn't make it any better. — There's a reason why you don't see anything like Prototype nowadays because that is, in fact, still very much frowned upon. You may extend global objects, and it's still bad practice. — If the DOM ends up adding Element.prototype.setAttributes and its signature doesn't match yours, good luck finding your future bugs. — A note doesn't save the answer, it's still downvotable because its code is bug-prone.
|
15

You could code an ES5.1 helper function:

function setAttributes(el, attrs) {
    Object.keys(attrs).forEach(key => el.setAttribute(key, attrs[key]));
}

Call it like this:

setAttributes(elem, { src: 'http://example.com/something.jpeg', height: '100%' });

Comments

10

You can create a function that takes a variable number of arguments:

function setAttributes(elem /* attribute, value pairs go here */) {
    for (var i = 1; i < arguments.length; i+=2) {
        elem.setAttribute(arguments[i], arguments[i+1]);
    }
}

setAttributes(elem, 
    "src", "http://example.com/something.jpeg",
    "height", "100%",
    "width", "100%");

Or, you pass the attribute/value pairs in on an object:

 function setAttributes(elem, obj) {
     for (var prop in obj) {
         if (obj.hasOwnProperty(prop)) {
             elem[prop] = obj[prop];
         }
     }
 }

setAttributes(elem, {
    src: "http://example.com/something.jpeg",
    height: "100%",
    width: "100%"
});

You could also make your own chainable object wrapper/method:

function $$(elem) {
    return(new $$.init(elem));
}

$$.init = function(elem) {
    if (typeof elem === "string") {
        elem = document.getElementById(elem);
    }
    this.elem = elem;
}

$$.init.prototype = {
    set: function(prop, value) {
        this.elem[prop] = value;
        return(this);
    }
};

$$(elem).set("src", "http://example.com/something.jpeg").set("height", "100%").set("width", "100%");

Working example: http://jsfiddle.net/jfriend00/qncEz/

Comments

7
const setAttributes = (el, attrs) =>
  Object.entries(attrs)
    .forEach(args =>
      el.setAttribute(...args))

Comments

5

you can simply add a method "setAttributes" (with "s" at the end) to "Element" prototype like this:

Element.prototype.setAttributes = function(obj){
  for(var prop in obj) {
    this.setAttribute(prop, obj[prop])
  }
}

P.S: you can define it in one line:

Element.prototype.setAttributes = function(obj){ for(var prop in obj) this.setAttribute(prop, obj[prop]) }

and you can call it normally as you call the other methods. The attributes are given as an object:

elem.setAttributes({"src": "http://example.com/something.jpeg", "height": "100%", "width": "100%"})

you can add an "if" statement to throw an error if the given argument is not an object.

1 Comment

Now it makes sense. I was wondering how to do this kind of change to a predefined function. Thanks!
4

Or create a function that creates an element including attributes from parameters

function elemCreate(elType){
  var element = document.createElement(elType);
  if (arguments.length>1){
    var props = [].slice.call(arguments,1), key = props.shift();
    while (key){ 
      element.setAttribute(key,props.shift());
      key = props.shift();
    }
  }
  return element;
}
// usage
var img = elemCreate('img',
            'width','100',
            'height','100',
            'src','http://example.com/something.jpeg');

FYI: height/width='100%' would not work using attributes. For a height/width of 100% you need the elements style.height/style.width

6 Comments

@Chris - it was random yes, because I wanted to promote this answer instead, so I had to downvote the answer above it. and yes, if you have 1000 items and you must change 5 attributes for each, it would be best to re-create them with the new attributes than to access the DOM 5000 times, wouldn't you agree?
@vsync if you are using a random copy/paste function you found on StackOverflow without considering the special performance concerned inherit to your use case, then you probably have a bigger issue. Further, in the answer you downvoted, the DOM would not be accessed 5000 times, no more so than this answer -- in both cases, the element in question has not been inserted into the DOM tree. This answer and mine do the same thing, we simply iterate the properties differently.
@Chris - This question does not concerns me. why are you talking about me and what I do or not? it's irrelevant. Your answer isn't very good if one needs to change many nodes' attributes on the DOM itself, while this answer is slightly better because it promotes a good way of thinking, where you re-create the node with all it's attributes and re-install it in the DOM. This also isn't the idealr, because using the clone method would be preferred. No need creating the whole node from scratch. Anyway, it's top priority to minimize access to the DOM, the most common use case.
@vsync The word "you" is used in an abstract sense, not meaning you as an individual (which I am pretty sure you, vsynch, know) but to the hypothetical future consumer of these answers. Once again, the two answers are identical in function. You're free to vote how you want to, even if your reasoning is flawed (check benchmarks), but keep your condescending remarks to yourself.
maybe it is faster...because cloning might be heavy.
|
4

Try this

function setAttribs(elm, ob) {
    //var r = [];
    //var i = 0;
    for (var z in ob) {
        if (ob.hasOwnProperty(z)) {
            try {
                elm[z] = ob[z];
            }
            catch (er) {
                elm.setAttribute(z, ob[z]);
            }
        }
    }
    return elm;
}

DEMO: HERE

1 Comment

I found this wouldn't see the fill attribute of an SVG circle. I had to use setAttribute not elm[z]=obj[z]
3

That's an easy way

let div = document.getElementsByTagName("div")[0];

let attr = ["class", "id", "title"];
let attrVlu = ["ahmed", "mohamed", "ashraf"];

for(let i = 0; i < 3; i++) {
    div.setAttribute(attr[i], attrVlu[i]);
}

Comments

2

No function example:

let checkbox = document.createElement('input');

for (const [key, value] of Object.entries({
       type: 'checkbox',
       id: 'sys-surname',
       class: 'switcher23',
       value: 1,
       name: 'surname'
 })) {
       checkbox.setAttribute(key, value);
  }

Comments

1

use this function to create and set attributes at the same time

function createNode(node, attributes){
    const el = document.createElement(node);
    for(let key in attributes){
        el.setAttribute(key, attributes[key]);
    }
    return el;
}

use it like so

const input = createNode('input', {
    name: 'test',
    type: 'text',
    placeholder: 'Test'
});
document.body.appendChild(input);

Comments

1

I guess it's best way to set attributes at once for any element in this class.

function SetAtt(elements, attributes) {
    for (var element = 0; element < elements.length; element++) {
        for (var attribute = 0; attribute < attributes.length; attribute += 2) {
            elements[element].setAttribute(attributes[attribute], attributes[attribute + 1]);
        }
    }
}
var Class = document.getElementsByClassName("ClassName"); // class array list
var Data = ['att1', 'val1', 'att2', 'val2', 'att3', 'val3']; //attributes array list
SetAtt(Class, Data);

Comments

1
let elem = document.createElement("img");
Object.entries({"src": "http://example.com/something.jpeg"),
                "height": "100%",
                "width": "100%"}).forEach(kv => elem.setAttribute(kv[0], kv[1]));

1 Comment

Why re-repeat other answers? For example, 2018 that is even shorter: stackoverflow.com/a/49594448/5113030
1
var elem = document.createElement("img");

function setAttributes(attributes) {
    for (let key in attributes) {
    elem.setAttribute(key, attributes[key]);
    }
}



setAttributes({src: "http://example.com/something.jpeg",height: "100%",width: "100%",});

1 Comment

Welcome to SO. Please don't post code-only answers but add a little textual explanation about how and why your approach works and how it differs from the other answers given.
0

The most simple way is:

Create an array with objects into him, like: array = [{obj1}, {obj2}, etc...]

next, you iterate on array to set the key's object like the

attribute and the value's object like the value of attribute:

example: let arr = [{'id': 'myId'}, {'class': 'myClassname'}]

/iterate on array/

function setAt(array){

    for (attr of array){
        myElement.setAttribute(attr, array[attr])
    }
}

later, you call the function passing your array like args: setAt(arr)

1 Comment

This answer was provided years ago.
-2

THE EASIEST: ` var elem = document.createElement("img");

var attrs = { src: "http://example.com/something.jpeg", height: "100%", width: "100%" }

Object.assign(elem, attrs); `

1 Comment

This is a copy of the already the accepted answer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.