jQuery: Selecting and manipulating html elements outside the DOM

30,576

Solution 1

I'm correcting my incorrect comment. Yes, you can do something like this, but reading the jQuery documentation, it is said that the code is inserted in the DOM http://api.jquery.com/jQuery/#jQuery2. So, even the code below seems to not insert nothing in the DOM, it is indeed inserted.

Try this:

var codeToProcess = "<div>" +
                    "    <div id='myDiv1'>a</div>" +
                    "    <div id='myDiv2'>b</div>" +
                    "    <div id='myDiv3'>c</div>" +
                    "</div>";

var $toProcess = $( codeToProcess );
$toProcess.find( "div" ).addClass( "processed" );

// getting by id before insertion
alert( $toProcess.find( "#myDiv1" ).html() );
alert( $( "#myDiv1" ).html() ); // this will return null, since the divs
                                // were not yet added to the document

$toProcess.appendTo( "#container" );
// or $( "#container" ).html( $toProcess );

// getting by id after insertion
alert( $( "#myDiv2" ).html() );

jsFiddle: http://jsfiddle.net/davidbuzatto/me7T3/

Edit:

To insert code from a external file, you can use the load function. You can see an example here: http://jsfiddle.net/davidbuzatto/zuFsc/ Note that in this example I used the echo service os jsFiddle to emulate a external file. Take a look here How do you output a view file as an ajax response in Java? and here http://api.jquery.com/load/

Solution 2

You can use javascript to manually create DOM elements that are not inserted into the DOM hierarchy and you can manipulate them as much as you want before inserting them into the DOM.

But, if you're trying to manipulate DOM elements that are created by your page HTML before that page HTML has been parsed, you cannot do that. The DOM elements don't exist at that point so there's nothing to manipulate unless you manually created them as described in the first paragraph.

Some operations only work on DOM elements inserted into the DOM hieararchy such as document.getElementById(), but other methods can be used on a piece of DOM that isn't in the main hierarchy such as item.getElementsByClassName() where item is a DOM element not in the DOM hierarchy.

In jQuery, the default context is the document so a simple selector operation like $(".foo") will only search DOM elements in the DOM document hierarchy. But, if you pass a specific context, $(".foo", item), then the jQuery selector will search that context, not the main document.

Share:
30,576

Related videos on Youtube

Ben Pearce
Author by

Ben Pearce

I'm a freelance programmer located in San Francisco. I specialize in full lifecycle development of apps leveraging web services.

Updated on December 08, 2020

Comments

  • Ben Pearce
    Ben Pearce over 3 years

    As far as I can tell only objects that have been loaded into the DOM can be manipulated with selectors. This is illustrated in the example below, when the button is clicked it's click handler un-successfully tries to select an element in the page to be loaded and change it's html before. I surmise that because the click handler is triggered before the link page is loaded into the DOM the selector doesn't effect the element.

    My question is, is there any way to instantiate an external chunk of html and manipulate it before inserting it into the DOM.

    script_1.js:

    $(document).ready(function () {
        $("#testButton").click(function () {
            $("#externalPageDiv").html("hello world");
        });
    });
    

    External Page html:

    <head>
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
        <link rel="stylesheet" href="http://code.jquery.com/mobile/1.1.0-rc.1/jquery.mobile-1.1.0-rc.1.min.css"
        />
        <script src="http://code.jquery.com/jquery-1.7.1.min.js"></script>
        <script src="http://code.jquery.com/mobile/1.1.0-rc.1/jquery.mobile-1.1.0-rc.1.min.js"></script>
        <script src="script_1.js"></script>
    </head>
    
    <body>
        <div data-role="page" id="externalPage" data-add-back-btn="true">
            <div data-role="content" id="externalPageContent">
                <div id="externalPageDiv"></div>external page</div>
        </div>
    </body>
    

    Main Page Html:

    <head>
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
        <link rel="stylesheet" href="http://code.jquery.com/mobile/1.1.0-rc.1/jquery.mobile-1.1.0-rc.1.min.css"
        />
        <script src="http://code.jquery.com/jquery-1.7.1.min.js"></script>
        <script src="http://code.jquery.com/mobile/1.1.0-rc.1/jquery.mobile-1.1.0-rc.1.min.js"></script>
        <script src="script_1.js"></script>
    </head>
    
    <body>
        <div data-role="page" id="internalPage_1" data-add-back-btn="true">
            <div data-role="content" id="internalPageContent_1">
                <a href="externalPage.html" id="testButton" data-role="button" rel="external">Page Change</a>
            </div>
        </div>
        <div data-role="page" id="mainPage" data-add-back-btn="true">
            <div data-role="content" id="mainPageContent">Main Page</div>
        </div>
    </body>
    

    • davidbuzatto
      davidbuzatto almost 12 years
      <strike>No, you can't. You need to insert the code first in the document.</strike> Sorry, I was wrong.
    • nnnnnn
      nnnnnn almost 12 years
      @davidbuzatto - Yes there is. You can retrieve a piece of html via Ajax, or generate it in JS/jQuery code, and manipulate it with jQuery prior to inserting it into the DOM.
    • davidbuzatto
      davidbuzatto almost 12 years
      @nnnnnn Something like $( "html code here" ).manipulations...?
  • nnnnnn
    nnnnnn almost 12 years
    "So, even the code below seems to not insert nothing in the DOM, it is indeed inserted." - The code you've shown explicitly inserts the dynamically created elements into the DOM with .appendTo("#container") (where "#container" already existed). The jQuery doco you link to doesn't really say that the elements are inserted into the DOM - it creates "DOM elements", but they're not in the DOM that represents the displayed page unless and until you insert them.
  • davidbuzatto
    davidbuzatto almost 12 years
    @nnnnnn: I agree, but I was referring to the "var $toProcess = $( codeToProcess );" code. The jQuery docs says that this code will insert the markup in DOM. jfriend00 seems to agree with it.
  • nnnnnn
    nnnnnn almost 12 years
    I can't see in the jQuery docs where it says that. In my opinion jfriend00's answer agrees with my position. If the $toProcess = $(codeToProcess) line actually inserted the newly created elements into the DOM then you'd be able to see them in the page, you wouldn't need to .appendTo()...
  • davidbuzatto
    davidbuzatto almost 12 years
    @nnnnnn: Just try my fiddle and remove the append. You will not see the inserted code. jQuery docs: If a string is passed as the parameter to $(), jQuery examines the string to see if it looks like HTML (i.e., it has <tag ... > somewhere within the string). If not, the string is interpreted as a selector expression, as explained above. **But if the string appears to be an HTML snippet, jQuery attempts to create new DOM elements as described by the HTML. Then a jQuery object is created and returned that refers to these elements. You can perform any of the usual jQuery methods on this object**
  • Ben Pearce
    Ben Pearce almost 12 years
    What I'd like to do is select an element from an external DOM, Manipulate it's element, and then insert it into the current DOM. I tried to implement the suggestion on your last para graph to this end but with out success. If I wanted to select the element wiht id = "externalPageDiv" from the html file externalHtml.html would the code be $("#externalPageDiv", "externalHtml.html").getElementById(...);
  • jfriend00
    jfriend00 almost 12 years
    @BenPearce - you can't run DOM queries on a text file. If it's in the same domain, you could load it into a detached DOM element using jQuery's .load() and then use DOM search functions on that detached element.
  • Ben Pearce
    Ben Pearce almost 12 years
    Hi David, thank you for the example. This is helpful but still missing two pieces I need. The first being how to import the initial html string from an external file. The second being how to select elements by id from the $toProcess variable (I unsuccessfully tried to incorporate this into the fiddle).
  • Ben Pearce
    Ben Pearce almost 12 years
    It seems very OOP unfriendly if html templates can't be instantiated with out adding them to the DOM.
  • jfriend00
    jfriend00 almost 12 years
    @BenPearce - I don't know why this has anything to do with OOP. To manipulate data in a file, it has to be loaded into some sort of data structure that the CPU can access. To use DOM manipulation functions on it, it has to be loaded into a DOM element. You don't have to put it into the page. You can create a DOM element that is not in the page and load the template into that and use DOM functions on that. But, to no surprise, DOM functions only work on DOM elements so you have to put the template into DOM elements before you can use DOM functions on it. Seems pretty logical to me.
  • Ben Pearce
    Ben Pearce almost 12 years
    I guess I'm confused about the difference between the DOM and the page. How do you insert an element into the DOM without inserting it into the page?
  • nnnnnn
    nnnnnn almost 12 years
    OK, the section of the doco that you quoted doesn't say the new elements are added to the DOM. Neither does the rest of that page. They will be "DOM elements", but they're not actually added to the DOM - read it again more carefully, and then use your browser's debug tools to inspect the DOM and you won't find the elements until after you append them.
  • jfriend00
    jfriend00 almost 12 years
    @BenPearce - var item = document.createElement("div"); creates a DOM element that is not in the page. It could be inserted into the page with .appendChild() or used for your purposes as is without putting it into the page.
  • davidbuzatto
    davidbuzatto almost 12 years
    @BenPearce: Ben, I updated my fiddle to get the inserted elements by id (before and after insertion). I inserted in my post a link to an example of how to load external files too.