4

I am trying to append the contents of a .html file to the body of my main page. Basically, I am trying to make a reusable chunk of html that I can load into any page with a simple JavaScript function.

Here is the content of my nav bar, the content I want to reuse:

<div id = "navbar">
  <div class = "Tab">
    <h1>Home</h1>
  </div>
  <div class = "Tab">
    <h1>Contact</h1>
  </div
</div>

That is in a file called navbar.html

Now in my main index.html I want to import it by doing something like this:

<head>
  <script src = "importHTML.js" type = "text/javascript"></script>
</head>

<body>
  <script type = "text/javascript">
    importHTML("navbar.html");
  </script>
</body>

That should take care of importing the html in navbar.html.

The content of importHTML.js is this:

function importHTML(url_) {
  var request = new XMLHttpRequest();

  request.addEventListener("load", function(event_) {
    //This is the problem line of code
    //How do I get the contents of my response to act like an element?  
    document.body.appendChild(this.responseText);
  }, false);

  xmlhttprequest.open("POST", url_, true);
  xmlhttprequest.send(null);
}

So, I guess my question is pretty simple: How do I convert that response text to an HTML element so I can append all of it to the body?

zer00ne
  • 41,936
  • 6
  • 41
  • 68
Frank
  • 2,050
  • 6
  • 22
  • 40
  • You need to `createElement` first, you can't just append a text string as a child. [See MDN's Example](https://developer.mozilla.org/en-US/docs/Web/API/Node/appendChild#Example) for more info on what you'll need to do. – romellem Apr 05 '16 at 14:52
  • Why are you doing this with ajax instead of some server-side language? or some build-task? – Kevin B Apr 05 '16 at 15:14
  • Actually, @Kevin B, you are right. All I'm doing is calling back to the server, anyway. I might as well do all the work on the back end before I serve it and avoid the second call. But if I don't control the server like on a github pages site, AJAX might come in handy. – Frank Apr 05 '16 at 15:53
  • @Frank What exactly are you trying to do? I thought you needed to import HTML into another page. My demo shows the import of 2 HTML tables from 2 different pages by jQuery and JavaScript. – zer00ne Apr 05 '16 at 22:00

6 Answers6

5

Ajax HTML Injection

jQuery $.get() and JavaScript XMLHttpRequest()

This is a demonstration of 2 ways to inject, include, import, etc. There's 3 pages:

  1. index.html
    • It has 2 links and 2 divs
  2. data1.html
    • It's data will be imported to index.html by $.get()
  3. data2.html
    • It's data will be imported to index.html by XMLHttpRequest()

I added jQuery to show the difference in complexity, but they do the same thing. The live demo is at the end of this mess.

jQuery $.get() Setup

HTML on index.html

div#data1 is the element that'll have the HTML of data1.html appended to it.

     <h3 id="import1">
        <a href="">Import data1.html by jQuery<code>$.get()</code></a>
     </h3>
     <div id="data1"></div>

jQuery on index.html

$('#import1').on('click', function(e) {
    e.preventDefault();
    $.get('data1.html', function(data) {
        $("#data1").html(data);
    });
});     

JavaScript XMLHttpRequest() Setup

HTML on index.html

div[data-x] is the element that'll have the HTML of data2.html appended to it.

<h3 id="import2">
    <a href="">
        Import data2.html by JavaScript<code>XMLHttpRequest()</code>
    </a></h3>
<div data-x="data2.html"></div>

javaScript on index.html

          function xhr() {
             var tags, i, clone, file, xhttp;
             tags = document.getElementsByTagName("*");
             for (i = 0; i < tags.length; i++) {
               if (tags[i].getAttribute("data-x")) {
                 clone = tags[i].cloneNode(false);
                 file = tags[i].getAttribute("data-x");
                 xhttp = new XMLHttpRequest();
                 xhttp.onreadystatechange = function() {
                 if (xhttp.readyState == 4 && xhttp.status == 200) {
                   clone.removeAttribute("data-x");
                   clone.innerHTML = xhttp.responseText;
                   tags[i].parentNode.replaceChild(clone, tags[i]);
                   xhr();
                 }
                }
                xhttp.open("GET", file, true);
                xhttp.send();
                return;
              }
            }
          }


     document.getElementById('import2').addEventListener('click', function(e) {
       e.preventDefault();
       xhr();
     }, false);

README.md

Plunker

Note: This demo relies on user interaction via anchor links. This of course is probably not exactly what you need. You probably want it automatically loaded, so the following modifications are needed:

jQuery

$(function() {
    $.get('data1.html', function(data) {
        $("#data1").html(data);
    });
});

JavaScript

(function xhr() {
        xhr();
             var tags, i, clone, file, xhttp;
             tags = document.getElementsByTagName("*");
             for (i = 0; i < tags.length; i++) {
               if (tags[i].getAttribute("data-x")) {
                 clone = tags[i].cloneNode(false);
                 file = tags[i].getAttribute("data-x");
                 xhttp = new XMLHttpRequest();
                 xhttp.onreadystatechange = function() {
                 if (xhttp.readyState == 4 && xhttp.status == 200) {
                   clone.removeAttribute("data-x");
                   clone.innerHTML = xhttp.responseText;
                   tags[i].parentNode.replaceChild(clone, tags[i]);
                   xhr();
                 }
                }
                xhttp.open("GET", file, true);
                xhttp.send();
                return;
              }
            }
          })();
zer00ne
  • 41,936
  • 6
  • 41
  • 68
  • How is this invalid downvoter? Explain why this does not resolve or relate to the question? – zer00ne Apr 05 '16 at 17:17
  • This is a great answer. Ultimately I want something like HTML Imports, but until that functionality gets better support I'll be using AJAX. – Frank Apr 05 '16 at 22:37
  • Thank you, sir. Indeed, HTML Imports would be so convenient. – zer00ne Apr 05 '16 at 22:46
0

Interestingly there is an upcoming W3C draft for HTML imports https://www.w3.org/TR/html-imports/

Until then we can append the required markup to the DOM using Javascript.

JQuery approach

$(document).ready(function(){
    $( "body" ).load( "navbar.html" );
});
Fintan Kearney
  • 743
  • 7
  • 15
  • I looked into this before and it would be awesome if it were supported already. Right now I don't think there's support in Safari or IE. – Frank Apr 05 '16 at 18:31
-1

Js haven't native method for this task, but you can use jquery method load

${element}.load('./template.html');

Or, create element-container, and use innerHTML prop

request.addEventListener("load", function(event_) {
    //This is the problem line of code
    //How do I get the contents of my response to act like an element? 
    var container = document.createElement("div");
    container.innerHTML = this.responseText;
    document.body.appendChild(container);
}, false);

UPD
Convert string to DOM.

function strToDom(str) {
    var tempEl = document.createElement('div');
    tempEl.innerHTML = str;
    return tempEl.children[0];
}

NOTE: string element should be one root element, that wraps others

<div> ... </div>

not

<div></div><div></div>


ThisMan
  • 290
  • 1
  • 10
  • 2
    if javascript native can't do it, neither can jQuery. You just proved yourself wrong. – Kevin B Apr 05 '16 at 14:57
  • @KevinB js has method, that can convert `string` to `DOM`? Nope, need some manipulate to do this – ThisMan Apr 05 '16 at 15:00
  • @KevinB and my answer has second part with pure js implementation – ThisMan Apr 05 '16 at 15:02
  • I can add the responseText to the innerHTML of the newly created div and then append its child elements, thus avoiding adding an unwanted div container and converting my string to html. – Frank Apr 05 '16 at 15:12
  • I gave it a try myself and decided that it's not quite what I'm looking for. I think until HTML imports get better support, I'm just going to use my server to piece everything together. At best if I use Javascript I'm serving the content, then requesting more content and serving that, I might as well just serve it all at once. – Frank Apr 05 '16 at 18:34
-1

The importHTML.js file will look like this :

function importHTML(url_) {
  var request = new XMLHttpRequest();
  request.addEventListener("load", function(event_) {
  var iDiv = document.createElement('div');
iDiv.innerHTML = this.responseText;
document.getElementsByTagName('body')[0].appendChild(iDiv);
  }, false);

  request.open("POST", url_, true);
  request.send(null);
     }
Hitesh Dabhi
  • 118
  • 12
-2

I assume you can create a div and then modify the div.innerHTML to have the content of the response:

function importHTML(url_) {
  var request = new XMLHttpRequest();

  request.addEventListener("load", function(event_) {

    var myDiv = document.createElement("div")
    myDiv.innerHTML = this.responseText

    document.body.appendChild(myDiv);
  }, false);

  xmlhttprequest.open("POST", url_, true);
  xmlhttprequest.send(null);
}
E.Serra
  • 1,495
  • 11
  • 14
  • That will work, but then my html will be nested in a div. It would be ideal to convert the response text and then simply add it without having to nest it. – Frank Apr 05 '16 at 15:01
  • Then you would have 2 html definitions, 2 head definitions etc etc, you would have one html document inside the body of another one. I answered your question because it looks interesting, but this doesn't seem the way to do things, you can use include from jquery as suggested by thisMan, something along the lines of that is what I would do. Another option is to have pieces of js that create the html you want, instead of importing html, and calling them as – E.Serra Apr 05 '16 at 15:10
-2

you need a reference to DOM to know where to innest your loaded page. in your case you could think about appending it to body like this:

function importHTML(url_) {
  var request = new XMLHttpRequest();

  request.addEventListener("load", function(event_) {

    document.body.innerHTML += this.responseText

  }, false);

  xmlhttprequest.open("POST", url_, true);
  xmlhttprequest.send(null);
}