Ryan
Ryan

Reputation: 18109

Get selected element's outer HTML

I'm trying to get the HTML of a selected object with jQuery. I am aware of the .html() function; the issue is that I need the HTML including the selected object (a table row in this case, where .html() only returns the cells inside the row).

I've searched around and found a few very ‘hackish’ type methods of cloning an object, adding it to a newly created div, etc, etc, but this seems really dirty. Is there any better way, or does the new version of jQuery (1.4.2) offer any kind of outerHtml functionality?

Upvotes: 816

Views: 485935

Answers (30)

Rehmat
Rehmat

Reputation: 2299

Pure JavaScript:

var outerHTML = function(node) {
  var div = document.createElement("div");
  div.appendChild(node.cloneNode(true));
  return div.innerHTML;
};

Upvotes: 1

Sky Yip
Sky Yip

Reputation: 1089

jQuery plugin as a shorthand to directly get the whole element HTML:

jQuery.fn.outerHTML = function () {
    return jQuery('<div />').append(this.eq(0).clone()).html();
};

And use it like this: $(".element").outerHTML();

Upvotes: 0

Eric Hu
Eric Hu

Reputation: 18208

I believe that currently (5/1/2012), all major browsers support the outerHTML function. It seems to me that this snippet is sufficient. I personally would choose to memorize this:

// Gives you the DOM element without the outside wrapper you want
$('.classSelector').html()

// Gives you the outside wrapper as well only for the first element
$('.classSelector')[0].outerHTML

// Gives you the outer HTML for all the selected elements
var html = '';
$('.classSelector').each(function () {
    html += this.outerHTML;
});

//Or if you need a one liner for the previous code
$('.classSelector').get().map(function(v){return v.outerHTML}).join('');

EDIT: Basic support stats for element.outerHTML

Upvotes: 701

Mohamadjavad Vakili
Mohamadjavad Vakili

Reputation: 3338

You can also use get (Retrieve the DOM elements matched by the jQuery object.).

e.g:

$('div').get(0).outerHTML;//return "<div></div>"

As extension method :

jQuery.fn.outerHTML = function () {
  return this.get().map(function (v) {
    return v.outerHTML
  }).join()
};

Or

jQuery.fn.outerHTML = function () {
  return $.map(this.get(), function (v) {
    return v.outerHTML
  }).join()
};

Multiple choice and return the outer html of all matched elements.

$('input').outerHTML()

return:

'<input id="input1" type="text"><input id="input2" type="text">'

Upvotes: 18

Holly
Holly

Reputation: 7752

This is quite simple with vanilla JavaScript...

document.querySelector('#selector')

Upvotes: 3

evandrix
evandrix

Reputation: 6190

$.html = el => $("<div>"+el+"</div>").html().trim();

Upvotes: 1

Volomike
Volomike

Reputation: 24886

No need to generate a function for it. Just do it like this:

$('a').each(function(){
    var s = $(this).clone().wrap('<p>').parent().html();
    console.log(s);
});

(Your browser's console will show what is logged, by the way. Most of the latest browsers since around 2009 have this feature.)

The magic is this on the end:

.clone().wrap('<p>').parent().html();

The clone means you're not actually disturbing the DOM. Run it without it and you'll see p tags inserted before/after all hyperlinks (in this example), which is undesirable. So, yes, use .clone().

The way it works is that it takes each a tag, makes a clone of it in RAM, wraps with p tags, gets the parent of it (meaning the p tag), and then gets the innerHTML property of it.

EDIT: Took advice and changed div tags to p tags because it's less typing and works the same.

Upvotes: 346

rolacja
rolacja

Reputation: 2391

Short and sweet.

[].reduce($('.x'), function(i,v) {return i+v.outerHTML}, '')

or event more sweet with help of arrow functions

[].reduce.call($('.x'), (i,v) => i+v.outerHTML, '')

or without jQuery at all

[].reduce.call(document.querySelectorAll('.x'), (i,v) => i+v.outerHTML, '')

or if you don't like this approach, check that

$('.x').get().reduce((i,v) => i+v.outerHTML, '')

Upvotes: 2

SpYk3HH
SpYk3HH

Reputation: 22570

To make a FULL jQuery plugin as .outerHTML, add the following script to any js file and include after jQuery in your header:

update New version has better control as well as a more jQuery Selector friendly service! :)

;(function($) {
    $.extend({
        outerHTML: function() {
            var $ele = arguments[0],
                args = Array.prototype.slice.call(arguments, 1)
            if ($ele && !($ele instanceof jQuery) && (typeof $ele == 'string' || $ele instanceof HTMLCollection || $ele instanceof Array)) $ele = $($ele);
            if ($ele.length) {
                if ($ele.length == 1) return $ele[0].outerHTML;
                else return $.map($("div"), function(ele,i) { return ele.outerHTML; });
            }
            throw new Error("Invalid Selector");
        }
    })
    $.fn.extend({
        outerHTML: function() {
            var args = [this];
            if (arguments.length) for (x in arguments) args.push(arguments[x]);
            return $.outerHTML.apply($, args);
        }
    });
})(jQuery);

This will allow you to not only get the outerHTML of one element, but even get an Array return of multiple elements at once! and can be used in both jQuery standard styles as such:

$.outerHTML($("#eleID")); // will return outerHTML of that element and is 
// same as
$("#eleID").outerHTML();
// or
$.outerHTML("#eleID");
// or
$.outerHTML(document.getElementById("eleID"));

For multiple elements

$("#firstEle, .someElesByClassname, tag").outerHTML();

Snippet Examples:

console.log('$.outerHTML($("#eleID"))'+"\t", $.outerHTML($("#eleID"))); 
console.log('$("#eleID").outerHTML()'+"\t\t", $("#eleID").outerHTML());
console.log('$("#firstEle, .someElesByClassname, tag").outerHTML()'+"\t", $("#firstEle, .someElesByClassname, tag").outerHTML());

var checkThisOut = $("div").outerHTML();
console.log('var checkThisOut = $("div").outerHTML();'+"\t\t", checkThisOut);
$.each(checkThisOut, function(i, str){ $("div").eq(i).text("My outerHTML Was: " + str); });
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="https://rawgit.com/JDMcKinstry/ce699e82c7e07d02bae82e642fb4275f/raw/deabd0663adf0d12f389ddc03786468af4033ad2/jQuery.outerHTML.js"></script>
<div id="eleID">This will</div>
<div id="firstEle">be Replaced</div>
<div class="someElesByClassname">At RunTime</div>
<h3><tag>Open Console to see results</tag></h3>

Upvotes: 11

Darlesson
Darlesson

Reputation: 6162

You can find a good .outerHTML() option here https://github.com/darlesson/jquery-outerhtml.

Unlike .html() that returns only the element's HTML content, this version of .outerHTML() returns the selected element and its HTML content or replaces it as .replaceWith() method but with the difference that allows the replacing HTML to be inherit by the chaining.

Examples can also be seeing in the URL above.

Upvotes: 3

David V.
David V.

Reputation: 5708

2014 Edit : The question and this reply are from 2010. At the time, no better solution was widely available. Now, many of the other replies are better : Eric Hu's, or Re Capcha's for example.

This site seems to have a solution for you : jQuery: outerHTML | Yelotofu

jQuery.fn.outerHTML = function(s) {
    return s
        ? this.before(s).remove()
        : jQuery("<p>").append(this.eq(0).clone()).html();
};

Upvotes: 191

Re Captcha
Re Captcha

Reputation: 3133

What about: prop('outerHTML')?

var outerHTML_text = $('#item-to-be-selected').prop('outerHTML');

And to set:

$('#item-to-be-selected').prop('outerHTML', outerHTML_text);

It worked for me.

PS: This is added in jQuery 1.6.

Upvotes: 156

jessica
jessica

Reputation: 3131

Extend jQuery:

(function($) {
  $.fn.outerHTML = function() {
    return $(this).clone().wrap('<div></div>').parent().html();
  };
})(jQuery);

And use it like this: $("#myTableRow").outerHTML();

Upvotes: 91

gtournie
gtournie

Reputation: 4382

Here is a very optimized outerHTML plugin for jquery: (http://jsperf.com/outerhtml-vs-jquery-clone-hack/5 => the 2 others fast code snippets are not compatible with some browsers like FF < 11)

(function($) {

  var DIV = document.createElement("div"),
      outerHTML;

  if ('outerHTML' in DIV) {
    outerHTML = function(node) {
      return node.outerHTML;
    };
  } else {
    outerHTML = function(node) {
      var div = DIV.cloneNode();
      div.appendChild(node.cloneNode(true));
      return div.innerHTML;
    };
  }

  $.fn.outerHTML = function() {
    return this.length ? outerHTML(this[0]) : void(0);
  };

})(jQuery);

@Andy E => I don't agree with you. outerHMTL doesn't need a getter AND a setter: jQuery already give us 'replaceWith'...

@mindplay => Why are you joining all outerHTML? jquery.html return only the HTML content of the FIRST element.

(Sorry, don't have enough reputation to write comments)

Upvotes: 2

Tokimon
Tokimon

Reputation: 4142

I agree with Arpan (Dec 13 '10 5:59).

His way of doing it is actually a MUCH better way of doing it, as you dont use clone. The clone method is very time consuming, if you have child elements, and nobody else seemed to care that IE actually HAVE the outerHTML attribute (yes IE actually have SOME useful tricks up its sleeve).

But I would probably create his script a bit different:

$.fn.outerHTML = function() {
    var $t = $(this);
    if ($t[0].outerHTML !== undefined) {
        return $t[0].outerHTML;
    } else {
        var content = $t.wrap('<div/>').parent().html();
        $t.unwrap();
        return content;
    }
};

Upvotes: 44

Stefan Bookholt
Stefan Bookholt

Reputation: 51

If the scenario is appending a new row dynamically, you can use this:

var row = $(".myRow").last().clone();
$(".myRow").last().after(row);

.myrow is the classname of the <tr>. It makes a copy of the last row and inserts that as a new last row. This also works in IE7, while the [0].outerHTML method does not allow assignments in ie7

Upvotes: 4

Abdennour TOUMI
Abdennour TOUMI

Reputation: 93163

// no cloning necessary    
var x = $('#xxx').wrapAll('<div></div>').parent().html(); 
alert(x);

Fiddle here: http://jsfiddle.net/ezmilhouse/Mv76a/

Upvotes: 6

fishy
fishy

Reputation: 11

I came across this while looking for an answer to my issue which was that I was trying to remove a table row then add it back in at the bottom of the table (because I was dynamically creating data rows but wanted to show an 'Add New Record' type row at the bottom).

I had the same issue, in that it was returning the innerHtml so was missing the TR tags, which held the ID of that row and meant it was impossible to repeat the procedure.

The answer I found was that the jquery remove() function actually returns the element, that it removes, as an object. So, to remove and re-add a row it was as simple as this...

var a = $("#trRowToRemove").remove();            
$('#tblMyTable').append(a);  

If you're not removing the object but want to copy it somewhere else, use the clone() function instead.

Upvotes: 0

Ivan Chaer
Ivan Chaer

Reputation: 7100

I've used Volomike's solution updated by Jessica. Just added a check to see if the element exists, and made it return blank in case it doesn't.

jQuery.fn.outerHTML = function() {
return $(this).length > 0 ? $(this).clone().wrap('<div />').parent().html() : '';
};

Of course, use it like:

$('table#buttons').outerHTML();

Upvotes: 3

Andy E
Andy E

Reputation: 344517

To be truly jQuery-esque, you might want outerHTML() to be a getter and a setter and have its behaviour as similar to html() as possible:

$.fn.outerHTML = function (arg) {
    var ret;

    // If no items in the collection, return
    if (!this.length)
        return typeof arg == "undefined" ? this : null;
    // Getter overload (no argument passed)
    if (!arg) {
        return this[0].outerHTML || 
            (ret = this.wrap('<div>').parent().html(), this.unwrap(), ret);
    }
    // Setter overload
    $.each(this, function (i, el) {
        var fnRet, 
            pass = el,
            inOrOut = el.outerHTML ? "outerHTML" : "innerHTML";

        if (!el.outerHTML)
            el = $(el).wrap('<div>').parent()[0];

        if (jQuery.isFunction(arg)) { 
            if ((fnRet = arg.call(pass, i, el[inOrOut])) !== false)
                el[inOrOut] = fnRet;
        }
        else
            el[inOrOut] = arg;

        if (!el.outerHTML)
            $(el).children().unwrap();
    });

    return this;
}

Working demo: http://jsfiddle.net/AndyE/WLKAa/

This allows us to pass an argument to outerHTML, which can be

  • a cancellable function — function (index, oldOuterHTML) { } — where the return value will become the new HTML for the element (unless false is returned).
  • a string, which will be set in place of the HTML of each element.

For more information, see the jQuery docs for html().

Upvotes: 19

Zeeshan
Zeeshan

Reputation: 98

Simple solution.

var myself = $('#div').children().parent();

Upvotes: -4

Petar
Petar

Reputation: 1093

I have made this simple test with outerHTML being tokimon solution (without clone), and outerHTML2 being jessica solution (clone)

console.time("outerHTML");
for(i=0;i<1000;i++)
 {                 
  var html = $("<span style='padding:50px; margin:50px; display:block'><input type='text' title='test' /></span>").outerHTML();
 }                 
console.timeEnd("outerHTML");

console.time("outerHTML2");

 for(i=0;i<1000;i++)
 {                 
   var html = $("<span style='padding:50px; margin:50px; display:block'><input type='text' title='test' /></span>").outerHTML2();
  }                 
  console.timeEnd("outerHTML2");

and the result in my chromium (Version 20.0.1132.57 (0)) browser was

outerHTML: 81ms
outerHTML2: 439ms

but if we use tokimon solution without the native outerHTML function (which is now supported in probably almost every browser)

we get

outerHTML: 594ms
outerHTML2: 332ms

and there are gonna be more loops and elements in real world examples, so the perfect combination would be

$.fn.outerHTML = function() 
{
  $t = $(this);
  if( "outerHTML" in $t[0] ) return $t[0].outerHTML; 
  else return $t.clone().wrap('<p>').parent().html(); 
}

so clone method is actually faster than wrap/unwrap method
(jquery 1.7.2)

Upvotes: 2

inspiraller
inspiraller

Reputation: 463

This is great for changing elements on the dom but does NOT work for ie when passing in a html string into jquery like this:

$('<div id="foo">Some <span id="blog">content</span></div>').find('#blog').outerHTML();

After some manipulation I have created a function which allows the above to work in ie for html strings:

$.fn.htmlStringOuterHTML = function() {     
    this.parent().find(this).wrap('<div/>');        
    return this.parent().html();
};

Upvotes: 1

Andy
Andy

Reputation: 2179

you can also just do it this way

document.getElementById(id).outerHTML

where id is the id of the element that you are looking for

Upvotes: 9

vapcguy
vapcguy

Reputation: 7537

$("#myNode").parent(x).html(); 

Where 'x' is the node number, beginning with 0 as the first one, should get the right node you want, if you're trying to get a specific one. If you have child nodes, you should really be putting an ID on the one you want, though, to just zero in on that one. Using that methodology and no 'x' worked fine for me.

Upvotes: -2

Chris
Chris

Reputation: 4648

Anothe similar solution with added remove() of the temporary DOM object.

Upvotes: 2

mindplay.dk
mindplay.dk

Reputation: 7340

Note that Josh's solution only works for a single element.

Arguably, "outer" HTML only really makes sense when you have a single element, but there are situations where it makes sense to take a list of HTML elements and turn them into markup.

Extending Josh's solution, this one will handle multiple elements:

(function($) {
  $.fn.outerHTML = function() {
    var $this = $(this);
    if ($this.length>1)
      return $.map($this, function(el){ return $(el).outerHTML(); }).join('');
    return $this.clone().wrap('<div/>').parent().html();
  }
})(jQuery);

Edit: another problem with Josh's solution fixed, see comment above.

Upvotes: 2

Arpan Dhandhania
Arpan Dhandhania

Reputation: 65

I used Jessica's solution (which was edited by Josh) to get outerHTML to work on Firefox. The problem however is that my code was breaking because her solution wrapped the element into a DIV. Adding one more line of code solved that problem.

The following code gives you the outerHTML leaving the DOM tree unchanged.

$jq.fn.outerHTML = function() {
    if ($jq(this).attr('outerHTML'))
        return $jq(this).attr('outerHTML');
    else
    {
    var content = $jq(this).wrap('<div></div>').parent().html();
        $jq(this).unwrap();
        return content;
    }
}

And use it like this: $("#myDiv").outerHTML();

Hope someone finds it useful!

Upvotes: 7

Ben Regenspan
Ben Regenspan

Reputation: 10548

node.cloneNode() hardly seems like a hack. You can clone the node and append it to any desired parent element, and also manipulate it by manipulating individual properties, rather than having to e.g. run regular expressions on it, or add it in to the DOM, then manipulate it afterwords.

That said, you could also iterate over the attributes of the element to construct an HTML string representation of it. It seems likely this is how any outerHTML function would be implemented were jQuery to add one.

Upvotes: 3

brettkelly
brettkelly

Reputation: 28205

$("#myTable").parent().html();

Perhaps I'm not understanding your question properly, but this will get the selected element's parent element's html.

Is that what you're after?

Upvotes: -12

Related Questions