Dónal
Dónal

Reputation: 187529

refactor HTML-generating JavaScript

Unfortunately on my project, we generate a lot of the HTML code in JavaScript like this:

var html = new StringBuffer();
html.append("<td class=\"gr-my-deals\"><a href=\"").append(deal.url).append("\" target=\"_blank\">").append(deal.description).append("</a></td>");

I have 2 specific complaints about this:

  1. The use of escaped double quotes (\”) within the HTML string. These should be replaced by single quotes (‘) to improve readability.
  2. The use of .append() instead of the JavaScript string concatentation operator “+”

Applying both of these suggestions, produces the following equivalent line of code, which I consider to be much more readable:

var html = "<td class=’gr-my-deals’><a href=’" + deal.url + "’ target=’_blank’>" + deal.description + "</a></td>";

I'm now looking for a way to automatically transform the first line of code into the second. All I've come up with so far is to run the following find and replace over all our Javascript code:

Find:    ).append(  
Replace: +

This will convert the line of code shown above to:

html.append("<td class=\"gr-my-deals\"><a href=\"" + deal.url + "\" target=\"_blank\">" + deal.description + "</a></td>)";

This should safely remove all but the first 'append()' statement. Unfortunately, I can't think of any safe way to automatically convert the escaped double-quotes to single quotes. Bear in mind that I can't simply do a find/replace because in some cases you actually do need to use escaped double-quotes. Typically, this is when you're generating HTML that includes nested JS, and that JS contains string parameters, e.g.

function makeLink(stringParam) {

  var sb = new StringBuffer();
  sb.append("<a href=\"JavaScript:myFunc('" + stringParam + "');\">");
}

My questions (finally) are:

Cheers, Don

Upvotes: 1

Views: 773

Answers (5)

Michael Lorton
Michael Lorton

Reputation: 44376

Templating? Templating sucks! Here's the way I would write your code:

TD({ "class" : "gr-my-deals" },
   A({ href : deal.url,
       target : "_blank"},
     deal.description ))

I use a 20-line library called DOMination, which I will send to anyone who asks, to support such code.

The advantages are manifold but some of the most obvious are:

  • legible, intuitive code
  • easy to learn and to write
  • compact code (no close-tags, just close-parentheses)
  • well-understood by JavaScript-aware editors, minifiers, and so on
  • resolves some browser-specific issues (like the difference between rowSpan and rowspan on IE)
  • integrates well with CSS

(Your example, BTW, highlights the only disadvantage of DOMination: any HTML attributes that are also JavaScript reserved words, class in this case, have to be quoted, lest bad things happen.)

Upvotes: 0

user4903
user4903

Reputation:

There is a good reason why you should be using the StringBuffer() instead of string concatenation in JavaScript. The StringBuffer() and its append() method use Array and Array's join() to bring the string together. If you have a significant number of partial strings you want to join, this is known to be a faster method of doing it.

Upvotes: 0

Andrew Hedges
Andrew Hedges

Reputation: 21796

As Shog9 implies, there are several good JavaScript templating engines out there. Here's an example of how you would use mine, jQuery Simple Templates:

var tmpl, vals, html;

tmpl  = '<td class="gr-my-deals">';
tmpl += '<a href="#{href}">#{text}</a>';
tmpl += '</td>';

vals  = {
    href : 'http://example.com/example',
    text : 'Click me!'
};

html  = $.tmpl(tmpl, vals);

Upvotes: 1

Shog9
Shog9

Reputation: 159618

Consider switching to a JavaScript template processor. They're generally fairly light-weight, and can dramatically improve the clarity of your code... as well as the performance, if you have a lot of re-use and choose one that precompiles templates.

Upvotes: 4

rp.
rp.

Reputation: 17683

Here is a stringFormat function that helps eliminate concatenation and ugly replacment values.

function stringFormat( str ) {

    for( i = 0; i < arguments.length; i++ ) {
        var r = new RegExp( '\\{' + ( i ) + '\\}','gm' );

        str = str.replace( r, arguments[ i + 1 ] );    
    }
    return str;
}

Use it like this:

var htmlMask = "<td class=’gr-my-deals’><a href=’{0}’ target=’_blank’>{1}</a></td>";

var x = stringFormat( htmlMask, deal.Url, deal.description ); 

Upvotes: 2

Related Questions