0

I am curious if there is an existing javascript framework that allows you to more easily create DOM in javascript.

Currently, I am changing the DOM like this:

var header_field = document.createElement('h1');
header_field.className = "header";
header_field.innerHTML = "This is the header";
parent_dom.appendChild(header_field);

... as an example.

Is there a framework that will say, interpret a javascript object, and manipulate the DOM based on that? I kind of envision something like:

jQuery.createDOM(
  [
    { element : 'h2', text : "This is the header", class : "header" }
  ]
);

... or something of that style.

For complex Ajax-Driven sites, I find myself typing a lot of repetitive code in order to create otherwise simple HTML. So, is there a framework out there that makes the process of manipulating the DOM in javascript considerably easier? Does jQuery already offer this and I just haven't heard of it?

GoldenNewby
  • 4,382
  • 8
  • 33
  • 44
  • maybe something like https://github.com/janl/mustache.js? – T I Mar 10 '12 at 00:53
  • 1
    **DOM = Document Object Model**. You don't _"create"_ or _"generate"_ DOM... you _manipulate the_ DOM. Server-side is infinitely better (SSI, PHP, etc.) than trying to use JavaScript to construct your pages from templates. – Sparky Mar 10 '12 at 00:54
  • What do you mean 'create DOM'? [jQuery](http://stackoverflow.com/questions/268490/jquery-document-createelement-equivalent), [MooTools](http://mootools.net/docs/core/Element/Element#Element:constructor) and other libraries do things like `createElement` and `appendChild` behind the scene. So I would say, yes, they create DOM. – Marshall Mar 10 '12 at 00:54
  • I have a bad habbit of never bothering to learn what different terms actually mean :p. I'll update the question. – GoldenNewby Mar 10 '12 at 01:01
  • never heard of dynamic dom? im surprised with these cynical remarks, i thought SO was a place to learn not act like ... – t q Mar 10 '12 at 01:03
  • @TomIngram Maybe I'm missing something, but isn't that more of a server-side system for generating HTML for clients that don't have javascript? – GoldenNewby Mar 10 '12 at 01:07
  • @tq, explain exactly what is "cynical" about any of these comments. Mine specifically, was factually correct and something anyone should be able to learn from. – Sparky Mar 10 '12 at 01:07
  • I work on a multi-million dollar project. Nearly all DOM material is generated on the cleint by JavaScript. The reasons for this are many but mostly for performance. – AutoSponge Mar 10 '12 at 01:09
  • @AutoSponge, what happens when visitors have JS turned off? Blank pages? As far as performance, you've simply shifted the load from the server to the client. – Sparky Mar 10 '12 at 01:10
  • @AutoSponge the system I'm working on manipulates the DOM based on dynamic API results. So I don't really see creating elements in javascript as an option, I was just hoping for an easier way of doing it. – GoldenNewby Mar 10 '12 at 01:12
  • @Sparky672 The system I am working on is privately licensed, and the users of it pay for it and accept that a requirement of using it is to enable javascript. It's not a publicly accessed site. – GoldenNewby Mar 10 '12 at 01:13
  • 3
    @sparky It's not a brochure, it's a web app. Web apps require JavaScript turned on. – AutoSponge Mar 10 '12 at 01:14
  • @GoldenNewby we bring several Mbs of json data down and merge it with templates and object methods. I think you'll find that a more efficient use of bandwidth than manipulating premade HTML. – AutoSponge Mar 10 '12 at 01:17
  • @AutoSponge, personally, I am in the camp that believes JS should never be turned off. Some of my pages are 100% dependent upon JS. However, I do not rely on client-side code to actually construct the pages from my templates. – Sparky Mar 10 '12 at 01:18
  • @AutoSponge When you say that you merge it with templates and object methods, what do you mean? – GoldenNewby Mar 10 '12 at 01:19
  • @GoldenNewby, whether or not JS is required for your app is totally beside the point. Others are going to read this thread in the future and maybe would like to be aware of the downside to heavy reliance on JS. – Sparky Mar 10 '12 at 01:20
  • @Sparky672 well, the reason our previous project failed and everyone was fired is because they said the same thing you did. They swore their post back architecture was modern. – AutoSponge Mar 10 '12 at 01:21
  • @Sparky672 I'd say everyone knows the downside of forcing a user to use JS, but then again I didn't know what DOM stood for. – GoldenNewby Mar 10 '12 at 01:21
  • 1
    @GoldenNewby we use some mustache style templating for static content. However, the more important part is how we use the json data to instantiate objects which know how to create their own HTML. This leaves us with very efficient veiw-models for each form element. We don't manipulate the DOM unless we need to and we don't query the DOM ever. That makes everything super fast and responsive. It's also very easy to reuse code. – AutoSponge Mar 10 '12 at 01:26
  • @AutoSponge, Bragging about some anonymous multi-million dollar project as the only basis to support your comments is meaningless... anyone could make such claims. Let's stick with technical details and the facts to support them. – Sparky Mar 10 '12 at 01:31
  • @Sparky672 "Server-side is infinitely better (SSI, PHP, etc.) than trying to use JavaScript to construct your pages from templates" feels more like a sensationalist view than a technical detail or a fact. – GoldenNewby Mar 10 '12 at 01:36
  • @GoldenNewby, that is my opinion, and yet the only person to challenge it does so by only saying _on my big project people got fired_ for thinking like that. I'm also here to learn... yet no explanation, facts, links, articles, etc. were presented to counter my opinion. It might just be possible that my chosen methods were best for my projects and others' methods were best for theirs. Unfortunately, we've _learned_ very little about that from these comments. – Sparky Mar 10 '12 at 01:43
  • @Sparky672 Yeah but isn't that true from his perspective too? Anyway, I appreciate your help in this topic (that's true for him too though). Take care! – GoldenNewby Mar 10 '12 at 01:46
  • @Sparky672 I'm hardly going to retype every blog article about template performance on my iPad in a comment block. I don't really care if you believe me, but HTML on the wire isn't always best. Gl golden – AutoSponge Mar 10 '12 at 02:15

5 Answers5

4

Writing repetitive code is completely avoidable. Whenever you find you've written the same code more than once or twice, encapsulate it in a function.

function h1(text) {
    return $("<h1>").addClass("header").text(text);
}

Take it a level deeper:

function el(name, className, text) {
    className = className || "";
    text = text || "";
    return $("<" + name + ">").addClass(className).text(text + "");
}
function h1 (text) {
    return el("h1", "header", text);
}

Keep going with it and you can do something like create an entire article by calling something like this:

function article(titleText, author, postDate, content) {
    return el("div", "article").append(
        h1(titleText),
        authorEl(author),
        dateEl(postDate),
        content);
}
$("#articles").append(article("some title", authors.Joe, new Date(), someContent));

Edit: If that's more than what you're looking for, jQuery does make it easier to create elements. For example, you could create a close button for every popup dialog on your page with something like this:

$("<div>").addClass("close").text("\xd7").prependTo(".dialog").click(function () {
    $(this).closest(".dialog").hide();
});

Similarly, add styles using .css({ backgroundColor: "#fff", border: "1px solid blue" }), add attributes using .attr({ type: "checkbox" }), properties: .prop({ checked: true }). The list goes on.

gilly3
  • 87,962
  • 25
  • 144
  • 176
  • By repetitive, I meant that I needed to go through the tedious process of using createElement, them modifying each individual attribute of that element 1 line at a time. I didn't mean to suggest that identical code was existing more than once. – GoldenNewby Mar 10 '12 at 01:04
  • @GoldenNewby - me too. Of course your code isn't line-for-line identical. That's what parameters are for. Pass the unique attributes as parameters to a function. If all you are trying to do is avoid calling `document.createElement()`, the jQuery equivelant is `$("
    ")`, and you can add multiple attributes at once using `.attr({ attr1: "value", attr2: "value" })` or `.prop()`.
    – gilly3 Mar 10 '12 at 01:18
  • Yeah I see what you are saying, that's a lot better. – GoldenNewby Mar 10 '12 at 01:24
  • I appreciate you taking the time to provide more information in your answer. I feel the accepted answer correctly answered my question before yours. Though I feel your answer is more detailed at this point. I gave you an up-vote regardless of the speed in which you answered. – GoldenNewby Mar 10 '12 at 01:39
1

In jQuery:

$('<h2 />').addClass('header').html('This is the header');

EDIT

Add this to your document and save a reference to it with, e.g.

var myHeader = $('<h2 />').addClass('header').html('This is the header');
$('body').append(myHeader);

Cheers

Madbreaks
  • 19,094
  • 7
  • 58
  • 72
  • Is there a way to then get access to the h2 element you just created? Can you link me to where you found this on jquery? – GoldenNewby Mar 10 '12 at 01:06
  • Updated answer to show how to save a reference to work with. I didn't "find this", it's just basic jQuery. Spend some time on the jQuery site, run through the "getting started" tutorials etc. You'll learn a lot. – Madbreaks Mar 10 '12 at 01:09
  • I am currently taking advantage of having the reference to the element in memory for the various functions which use it. I see creating id's for the elements as a more tedious workaround than simply manipulating the DOM line by line. – GoldenNewby Mar 10 '12 at 01:14
  • Updated my previous comment, and my answer. `id` not required. – Madbreaks Mar 10 '12 at 01:16
  • Cool, so basically jQuery returns the reference to the element for h2? This is looking like the answer to what I was looking for. – GoldenNewby Mar 10 '12 at 01:20
  • Or even more compact: `$('

    ', {'class': 'header', text: 'This is the header'})`.
    – Felix Kling Mar 10 '12 at 02:19
  • @FelixKling Actually yours is 61 chars, mine 58. But I digress. :) – Madbreaks Mar 10 '12 at 03:52
  • Sorry, I should have clarified, that's not what I meant. It just makes one function call instead of three to set up the element. Imagine you wanted to set attributes and styles as well, then you need two additional calls. Passing an object as second parameter seems to be a bit *leaner* imo (maybe that's a better term). It also closer to what the OP wants to do. – Felix Kling Mar 10 '12 at 10:37
1

You can abstract frequently used dom manipulation behind functions pretty easily:

function buildEntry(obj) {
    return [
        "<li",
        ( obj.class ? " " + obj.class : ""),
        ">",
        ( obj.header ? "<h2>" + obj.header + "</h2>" : "" ),
        ( obj.subheader ? "<h3>" + obj.subheader + "</h3>" : "" ),
        ( obj.content ? "<p>" + obj.content + "</p>" : "" ),
        "</li>"
    ].join("");
}
$.getJSON(url,data,function(){
    var strOutput = "";
    $.each(data,function(i,obj){
        strOutput += buildEntry(obj);
    });
    $("ul").html(strOutput);
});
Kevin B
  • 94,570
  • 16
  • 163
  • 180
  • A lot of the elements I create have eventhandlers which I set by using the returned value of createElement, so the solution would need to allow me to get the references to those created objects pretty easily. – GoldenNewby Mar 10 '12 at 01:10
  • you could use event delegation instead of binding events directly on multiple elements so that you end up with 1 event bound on the UL that listens for events bubbling up from the li's – Kevin B Mar 10 '12 at 01:41
  • using Event delegation also means when you update the list it doesn't have to rebind events. – Kevin B Mar 10 '12 at 01:41
  • Interesting point. It isn't applicable to my actual code, but thanks for sharing. – GoldenNewby Mar 10 '12 at 01:47
0

If you don't want to use jQuery, just do something like this:

 var h2 = '<h2 class="header">This is the header</h2>';
 parent_dom.innerHTML = h2; // use += to append

readable and quick to write.

If you are looking for a template system. Look at Underscore's template() function.

Guumaster
  • 389
  • 3
  • 10
  • In my case I'd like to get the references to each one of the elements created, so modifying it directly in innerHTML isn't an option. – GoldenNewby Mar 10 '12 at 01:05
0

Just create new elements with a function like this and give them an ID if you want to reference to it later:

function newElement(tag,class,text,id) {
if(!id) id='';
if(!class) class='';
return $('<' + tag + '>').addClass(class).html(text).attr('id',id);
}

Then you can do this:

newElement("h1","class-name-here","Hello, this is a header","id-here");

If you want to append it to the document, just do this (you don't even need to variable if you don't want):

var ele = newElement("h1","class-name-here","Hello, this is a header","id-here");
$('body').append(ele);
Nathan
  • 11,814
  • 11
  • 50
  • 93