2

I'm working on a little home brew project and I've found I've been spoiled by working with RoR and more specifically RoR partials.

My project is entirely client side. So I'm using javascript and HTML5. Now what I would like to do is this: have a home screen template with a container in which I could do something like the classic <%= yeild %> tag does in RoR.

I have thought about using iframes but that seems messy. I have also thought about using xmlHTTP requests to get the file in my javascript and then update the innerHTML of my content div with the file stream. I have done this before for personal projects, but it's hacky and I have to flag browsers like Chrome with a --allow-file-access-from-files tag. Which obviously I can't advise end users to do.

My other thought was to write the html as a javascript string, and then just put different strings as the value of content.innerHTML but this sounds stupid hard to maintain and just not clean at all.

Ultimately I am even up for writing my own solution (which I would then post here as the answer for anyone else looking) but I wanted to know if there was already a solution out there.

The ultimate end goal behavior would follow this flow:

Main_page:

<div id="main_content">
    <!-- this is the yield area -->
</div>

App starts and the file menu.html is loaded into the yield area:

<div id="main_content">
    <!-- this is the content of menu.html, notice it's like a partial, 
         there is no body or head or doc type tags, just a list -->
    <ul>
        <li>Menu item</li>
    </ul>
    <!-- this is the end of the menu.html content -->
</div> 

And finally when they click on Menu item it loads the contents of menu_item.html into the content div replacing the current content (menu.html).


Some research I already did:

Community
  • 1
  • 1
Ryan
  • 5,644
  • 3
  • 38
  • 66

2 Answers2

0

If you're using jQuery, you could use jQuery.load(): http://api.jquery.com/load/

Example:

$("#main_content").load("menu_item.html");
dinjas
  • 2,115
  • 18
  • 23
  • `.load()` is a shorthand for jquery AJAX, since both `main_page.html` and `menu.html` are going to be on the client side, not on a server where is the AJAX request supposed to go to retrieve the document? – Ryan Mar 26 '13 at 21:23
  • Hang on, I don't get it. This is a web page so of course you are going to have a server. That's the implied architecture. Are you doing something different instead? If so, you haven't said it in your question. – slebetman Mar 26 '13 at 23:31
0

If you're worried about the safety of the <div> (which is a good thing to be worried about), then what you'd be better off doing is using an intermediary <div> which is not attached to the DOM.

function parse_html (html) {
    var div = document.createElement("div");
    div.innerHTML = html;

    var scripts = div.getElementsByTagName("script"),
        i = scripts.length;

    while (i > 0) {
        div.removeElement(scripts[i]);
        i -= 1;
    }

    return div.firstChild;
}

Then if you grabbed an HTML file via XHR:

var xhr = new XMLHttpRequest();
xhr.open("GET", "/templates/menu.html", true);

You could put your var child_el = parse_html(xhr.responseText); in your XHR callback.
Then just append that element to your div.

That function is assuming that your partial has one root element (assuming that you could have multiple back-to-back partials, but each template would start from a single element.

If that's not the case, then you'd create a document fragment in the function (document.createDocumentFragment();) and append each of the elements in order, to the fragment, returning the fragment at the end of the function, which you would then append to the div (of course, this would make managing the nodes inside the div that much harder, after the fact).

I'm doing something similar to this for a few pet projects, using a simple template system built on {% %} for injecting data-properties ({% item.title %}) or arbitrary JS/return values from functions, within the html.

This is only a basic implementation, and there are lots of things you could do with this...
Supporting arbitrary nesting levels, for templates inside of templates is going to be more work.

Norguard
  • 26,167
  • 5
  • 41
  • 49
  • Browsers don't execute inline scripts attached by innerHTML anyway (it's one of the things people usually have to work around to get working) – slebetman Mar 26 '13 at 23:30
  • Indeed @slebetman But the last thing you want is the ghetto edge-cases. Also, for the browsers that abide, but are more restrictive, you don't want to subject your users to DOM security measures, because as far as I'm aware, handling the situation of an injected script tag is proprietary (ie: whether to throw an error, or just ignore it, or add it as an inert element with the hidden attribute, like style tags, et cetera). If I'm wrong and every browser implements this the exact same way, with no quirks (IE6+,Moz,O,Webkit,iP*d,android,etc), then that would be good for me to know. – Norguard Mar 27 '13 at 05:29
  • If you don't know it yet, yes every browser implements this the same exact way - the script is not executed and no errors are generated. – slebetman Mar 27 '13 at 15:48