views:

483

answers:

4

Hi,

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:

  • Is there a better way to safely replace the calls to 'append()' with '+'
  • Is there any way to safely replace the escaped double quotes with single quotes, regex?

Cheers, Don

+2  A: 

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 );
rp
Thanks, but ideally I'd what I need is a way to run this function over a large number of files. If a similar function was available as a Perl script, that would probably do the trick.
Don
+4  A: 

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.

Shog9
And for what it's worth, i wouldn't try converting code like this automatically. As ugly as the existing stuff is, the risk of introducing subtle bugs is worse. As you come across them, manually replace occurrences with a better method.
Shog9
John Resig's "micro-templating" is a very efficient and very concise bit of code. It also serves well if you are looking for a way to make coworkers do a double-take. This is somewhere in the posts you linked but I'll post it again: http://ejohn.org/blog/javascript-micro-templating/
Prestaul
It's a good suggestion, but not something that in the short term I'm really just looking for an automated way to improve the code (e.g. find-replace)
Don
+1  A: 

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);
Andrew Hedges
A: 

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.

hal10001
Faster maybe, but I don't believe the improvement in speed is worth the cost of maintainability.
Don
To each his own -- the method you are talking about is not going to be maintainable to every developer. FTW, the template systems mentioned, including John Resig's approach, use Array and join().
hal10001
@hal10001: you are correct WRT performance (not that it should make a big difference for the brief examples noted). But StringBuffer.append() is painfully verbose. Using array literals + join() ( ["<a href='", deal.url, "' target='_blank'>", deal.description, "</a>"].join("") ) would be preferable.
Shog9