views:

105

answers:

6

I have a lot of JavaScript code that creates HTML. For example:

function Reply(postId) {
    if (!document.getElementById("reply" + postId)) {
        $("#root" + postId).after("<div id='reply" + postId + "'><textarea cols='70' rows='8' style='margin-bottom: 10px'></textarea><br/><span style='margin-bottom: 30px'><input type='button' value='Submit' /><input type='button' value='Cancel' onclick='$(\"#reply" + postId + "\").remove();'/></span></div>");
    }
}

How can I use jQuery to make this more readable? What's the best way to go about making new elements in JavaScript? Can I see an example?

+1  A: 

The standard way is not to create html and then appending or prepending it but to create dom elements and adding them.

Please read this wonderful article on innerHTML vs DOM. by Tim Scarfe. It's very well written and and points and counter points.

You can read more on DOM here. and a Lot of information at the Gecko DOM Reference..

Sorry for only pasting links but it's a lot to go through.

If you want a quickstart. Look at this part of the Gecko DOM Reference. where they talk about createElement. Which is the magical method you're looking for.

Ólafur Waage
Creating DOM elements on the fly can be a real pain tho. I like templating (http://stackoverflow.com/questions/170168/jquery-templating-engines) when adding new markup on the fly.
wtaniguchi
Is that because it's faster to create DOM elements? I was under the impression that browsers optimize HTML rendering enough that innerHTML (or wrappers thereof) were faster.or is it to do with coding practices?
Thr4wn
*Shudder* - That looks like a really nasty hack for no good reason
Draemon
@Thr4wn: innerHTML is faster
Draemon
+1 for it being a complete pain in the ass to create even mildly complex HTML fragments with the DOM. Generate the HTML serverside and slap it in with innerHTML
Flubba
Read up on DOM and why this is the standard way to do this. And why innerHTML is something Microsoft created to "bypass" working with the DOM in the correct way. (And that other browsers had to comply since many people were wrongly using innerHTML)
Ólafur Waage
For example this note from MDC (https://developer.mozilla.org/en/DOM:element.innerHTML) "There is no public specification for this property (innerHTML), implementations differ widely. For example, when text is entered into a text input, IE will change the value attribute of the input's innerHTML property but Gecko browsers do not. It should never be used to write parts of a table—W3C DOM methods should be used for that—though it can be used to write an entire table or the contents of a cell."
Ólafur Waage
I said innerHTML was *faster*. jQuery doesn't just use innerHTML and it hides all the cross-browser issues. No amount of DOM evangelism will change the fact that it's slow and clumsy.
Draemon
@Draemon I was not directing my comments at you. I agree that innerHTML is clumsy to use.
Ólafur Waage
A: 

First of all you need to know where you want to append the HTML, here you'll see the documentation: for "manipulation": here.

So lets say you want to create a paragraph inside a DIV with the ID "insideme".

$("#insideme").append("<p>I'm adding this</p>");

That is for creation, now lets say you want to insert an existent DIV:

$("#insideme").append($("div#existent"));

Check the documentation, there you'll find every function that is used to add before, after, inside, etc.

Hope it helped you.

kuroir
A: 

Two ways:

  • Improve the formatting of that string
  • Install event handlers programatically

Eg:

function Reply(postId) {
    if (!document.getElementById("reply" + postId)) {
        // Generate HTML
        var html = "<div id='reply" + postId + "'>";
        html += "<textarea cols='70' rows='8' style='margin-bottom: 10px'></textarea><br/>";
        html += "<span style='margin-bottom: 30px'>";
        html += "<input type='button' value='Submit' />";
        html += "<input class='cancelButton' type='button' value='Cancel' />";
        html += "</span>";
        html += "</div>";

        // Insert into DOM
        $("#root" + postId).after(html);

        // Install event handlers
        $("#root .cancelButton").bind("click", function() {
            $("#reply" + postId).remove();
        });
    }
}

Using the DOM is methods directly is specifically discouraged by jQuery since it's so slow.

Update: As Chris says, move those styles to a CSS file to further tidy this up.

Draemon
A: 

If you want to fully use jquery functions, see if the following works (I have not tested it). Howerver, I would actually advise against this since I understand that direct HTML-string parsing/rendering is optimized a lot faster than a bunch of js function calls.

function Reply(postId) {
  var rid = "reply"+postId;
  if (!$('#'+rid)) {
    $('#root'+postID)
      .append("<div/>").attr('id',rid)
        .append("<textarea/>").attr({'cols',70,'row',8,'style','margin-bottom: 10px'})
        .after("<br/>")
        .after("<span />").attr('style','margin-bottom: 30px');
          .append("<input type='button' value='Submit' />")
          .after("<input type='button' value='Cancel' />")
          .onclick(function(){
             $("#"+rid).remove();
          });
  }
}
Thr4wn
A: 
  1. move the style stuff to a CSS file.
  2. remove the onclick event handler, replace it with a JQuery live.
  3. wrap the elementId in a varible.

    $(".cancelButton").live("click", function(){$(this).remove();});

    function Reply(postId) { var elementId = "reply" + postId; if (!document.getElementById(elementId )) { var element = $("#" + elementId).after("
    "); }

    }

Chris Brandsma
A: 

For such things I always use EJS.

http://embeddedjs.com/

Remove the angle brackets from your jQuery.

$( ".cancel" ).live( 'click', function() { $( this ).remove(); });

function reply( postId ) {
    if ( $( "#reply" + postId ).size() == 0 ) {
        var context = { postId: postId };
        $( "#root" + postId ).after(new EJS({ url: '/template.ejs' }).render( context ));
    }
}

Put them in a template with all their pointy little friends.

<div id="reply<%= postId %>">
    <textarea cols="70" rows="8" class="reply_editor"></textarea>
    <br>
    <span class="ok_cancel">
        <input type="button" value="Submit">
        <input type="button" value="Cancel" class="cancel">
    </span>
</div>

Inline styles are the devil's handiwork.

.reply_editor {
     margin-bottom: 10px
}
.ok_cancel {
    margin-bottom: 30px;
}

For extra legibility, don't attach handlers in your HTML. Attach them using jQuery.

Alan Gutierrez