views:

373

answers:

2

I need to convert a DOM element to a different type (as in HTML tag name, a to p in this case), but still retain all the original elements attributes. Whether they are valid for the new type or not doesn't matter in this case.

Any suggestions on how to do this?

I've looked at just creating a new element and copying the attributes across, but this isn't without it's own complications. In Firefox, DOMElement.attributes helpfully only includes attributes with a value, but in IE it reports all possible attributes for that element. The attributes property itself is read-only, so no way to copy that.

+2  A: 

while not a complete solution, the logic would basically be:

Save your existing element:

var oldElement = $(your selector here);

create a new element and insert it just before or after your oldElement

copy the attributes

  oldElement.attr().each(function(){
    copy old
    });

better yet, here is an example of a plug-in that does just what you want:

http://plugins.jquery.com/project/getAttributes

Mark Schultheiss
Brilliant, that'll do! Didn't realise attr() would return all attributes, and it fixes IE by only returning attributes with a value.
roryf
`attr()` can't be called with no args -- http://api.jquery.com/attr/
J-P
@J-P for some reason it worked the first time I tried it, but you're right it can't be called by that (I blame Firebug...)
roryf
there is a plugin to copy all attributes, if I find the reference I will add that.
Mark Schultheiss
+1  A: 

Sans-jQuery solution:

function makeNewElementFromElement( tag, elem ) {

    var newElem = document.createElement(tag),
        i, prop,
        attr = elem.attributes,
        attrLen = attr.length;

    // Copy children 
    elem = elem.cloneNode(true);
    while (elem.firstChild) {
        newElem.appendChild(elem.firstChild);
    }

    // Copy DOM properties
    for (i in elem) {
        try {
            prop = elem[i];
            if (prop && i !== 'outerHTML' && (typeof prop === 'string' || typeof prop === 'number')) {
                newElem[i] = elem[i];
            }
        } catch(e) { /* some props throw getter errors */ }
    }

    // Copy attributes
    for (i = 0; i < attrLen; i++) {
        newElem.setAttribute(attr[i].nodeName, attr[i].nodeValue);
    }

    // Copy inline CSS
    newElem.style.cssText = elem.style.cssText;

    return newElem;
}

E.g.

makeNewElementFromElement('a', someDivElement); // Create anchor from div
J-P
This is nice. What does this do wrt events attached to child elements? Do they get copied over too? (I'm thinking of IE and `attachEvent`). Would the first `while` loop be better served by `newElem.innerHTML = elem.innerHTML`?
Roatin Marth
This doesn't copy over events bound by `attachEvent` or `addEventListener`. AFAIK, there's no way to access event handlers registered via either of those methods. Also, `innerHTML` doesn't capture DOM properties, only attributes and content.
J-P