Monday, June 4, 2012

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?


Source: Tips4all

15 comments:

  1. 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();
    };

    ReplyDelete
  2. 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. On Firefox, you have to install Firebug.)

    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.

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


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

    ReplyDelete
  4. 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() {
    $t = $(this);
    if( "outerHTML" in $t[0] )
    { return $t[0].outerHTML; }
    else
    {
    var content = $t.wrap('<div></div>').parent().html();
    $t.unwrap();
    return content;
    }
    }

    ReplyDelete
  5. 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 val == "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().

    ReplyDelete
  6. 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
    $('.classSelector')[0].outerHTML

    ReplyDelete
  7. 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!

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

    (function($) {
    if (!$.outerHTML) {
    $.extend({
    outerHTML: function(ele) {
    var $return = undefined;
    if (ele.length === 1) {
    $return = ele[0].outerHTML;
    }
    else if (ele.length > 1) {
    $return = {};
    ele.each(function(i) {
    $return[i] = $(this)[0].outerHTML;
    })
    };
    return $return;
    }
    });
    $.fn.extend({
    outerHTML: function() {
    return $.outerHTML($(this));
    }
    });
    }
    })(jQuery);


    This will allow you to not only get the outerHTML of one element, but even get an object 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();


    For multiple elements

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

    ReplyDelete
  9. 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.

    ReplyDelete
  10. 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.

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

    ReplyDelete
  12. You can find a good .outerHTML() option here http://darlesson.com/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.

    ReplyDelete
  13. $("#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.

    ReplyDelete
  14. 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

    ReplyDelete
  15. $("#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?

    ReplyDelete