views:

227

answers:

6

I was wondering about this if people have strong opinions about the best way to generate HTML on the fly, especially with Ajax based applications.

Do you just create the HTML code using server side scripting and then send it out to the page or perhaps just return a JSON string and let Javascript do the job.

In my personal opinion, the first way ties the presentation layer way too much to the logic and makes it harder to change and a nightmare to maintain. The second way, although is my preferred method, also becomes a nightmare to maintain when the complexity of the project grows.

I was thinking of using a Javascript templating system as another layer, just to make the code more robust and less rigid. Anyone has good ideas of a light and really good JS templating system?

A: 

As far as your first question... I do both. I think it is really up to the individual and the specifics of the project to decide what will work better. If I am just updating some information, or adding to the DOM, I usually return the HTML directly. However, if I want to do things like add event handlers, custom css, etc, I do it via a JSON response. Just easier for me that way.

Your second question about a templating system, I am interested in an answer too.

sberry2A
+11  A: 

http://ejohn.org/blog/javascript-micro-templating/ is a devilishly brilliant hack for this. End result is very clean.

Jaanus
+1 Nice. Will have to try this soon.
sberry2A
A: 

If you want to preserve the MVC framework, you should let your template framework do the templating. The AJAX should only perform the server request, which performs all DB and business logic and then returns the URL to the template that should be loaded.

davidosomething
+1  A: 

We had a system where a lot of data was being passed as JSON from the server and then handled through a javascript templating engine on the client side. In .Net 4.0 (maybe even 3.5 sp1, i am not sure), this can be done using Client Templates.

I would prefer passing JSON over sending html. Its always good to keep data and view separate.

desigeek
+6  A: 

I too prefer a JSON response with client-side HTML creation logic.

Unfortunately, most real-world client-side HTML writing scripts are broken, containing many HTML-injection flaws that can easily become cross-site-scripting security holes. I think the belief is that because you're talking to your own server rather than directly to a hostile user you're somehow ‘safe’ and can get away without correctly strings when interpolating them into HTML. Which is of course nonsense.

I always see stuff like:

$('#mydiv').append('<em>Deleted '+response.title+'!</em>');

or:

mydiv.innerHTML= '<p>Renamed to '+response.name+'</p>;

or indeed Resig's microtemplating hack, where there is no HTML-escaping done by default. Come on, people! We've only just started cleaning up the legacy of broken PHP scripts serving up server-side XSS, now you want to introduce a whole new massive range of client-side XSS exploits?

Sigh. That's the Lure Of Strings. We think we understand them and can sling them together willy-nilly. But strings are treacherous, with hidden contexts and escaping requirements. If you must generate HTML on the client side you will need a function like this:

function h(s) {
    return s.split('&').join('&amp;').split('<').join('&lt;').split('"').join('&quot;');
}

mydiv.innerHTML= '<p>Renamed to '+h(response.name)+'</p>;

But personally I prefer DOM methods. Like with parameterisation for SQL, using the DOM methods takes the string-slinging out of the equation by talking raw strings directly to the components that will consume them. OK, the problem with the DOM is that it's rather verbose:

var p= document.createElement('p');
p.appendChild(document.createTextNode('Renamed to '+response.name))
mydiv.appendChild(p);

But you can always define helper functions to cut down on that, eg.:

mydiv.appendChild(makeElement('p', {}, 'Renamed to'+response.name));

(The new element creation stuff in jQuery 1.4 uses a similar style.)

bobince
If you plan to render a lot of HTML client side, DOM is way to slow.For the security aspect, if you parse your JSON instead of evaling it, I don't see any hole, it's just data. Am I missing something?
Mic
@Mic: Yes, you're missing HTML injection, the same reason you have to eg. use `htmlspecialchars` in PHP. Evaling JSON is actually perfectly safe as long as the server's JSON writer does it properly, which most do; the problem is that after evaluation you can be left with content in a string like `<script>stealCookies()</script>` or any number of other dangerous HTML constructs. If you're going to put literal text into `innerHTML`, you *must* HTML-encode it as with the `h()` function above, or you've got XSS: one user can hijack another user's interaction with the site.
bobince
Also “DOM is slow” is largely a myth. DOM is slow for a certain kind of operation, in particular inserting large numbers of nodes into the childNode list of an element with large numbers of children. This involves a load of list searching and can easily be O(n²), which is where the problems arise. The canonical example is adding rows to a large table. Other kinds of interaction with the document are not only safer with DOM, but also often faster than serialising a load of content to HTML, changing it and re-parsing it.
bobince
Large child node list manipulation can still be done efficiently with DOM through fragments and ranges, but unfortunately this is a bit more complicated to write, especially as IE's ranges implementation is very different from the standard. For this reason it is currently seldom done; I hope to see a library pick up this idea as it can be faster than DOM *or* innerHTML. One can also go for a mixed approach, like creating a load of `<tr>`​s through a repeated string written to `innerHTML` (fast!) then populating data and setting attributes on `rows[i].cells[j]` (secure).
bobince
I agree with your injection concerns if you are serve side, but if you inject the HTML client side with innerHTML, the script tags like your "stealCookies" example are not evaled, and thus harmless.
Mic
And for the speed, I do not agree with the myth version, DOM is awfully slow when you have to render serious HTML in the browser. Did you ever compare an XSLT/XML transformation and a DOM one, especially in IE? The template engine we built(PURE, to render HTML from JSON) was initially DOM based for elegancy, but quickly we had to drop the 100% DOM approach, and move to a mix of very limited DOM manipulations and use as much as possible innerHTML. You can have a look at it, the result is extremely fast and the programming is way simpler than DOM manipulations.
Mic
@Mic: setting `<script>` in innerHTML doesn't execute straight away, but depending on browser it can execute later on when inserted/moved in the document. Besides, you don't need to use a `<script>` block to inject script; other methods such as `onmouseover="..."`, `<img src="javascript:...">` and `style="someproperty: expression(...)"` are just as good.
bobince
(And of course XSLT is faster than lots of little DOM operations. It's doing it all in one go that makes it fast, not anything to do with text processing versus DOM. If the browser has to re-find list indexes on every little suboperation or worst of all if it does a page reflow after every change, the results are going to be poor. There are ways to avoid it.)
bobince
@bobince: A big thanks for the other script threats, do you have some others under the hood? Or an url with good resources about it? For the speed, the initial rendering of a big block of HTML is faster with text processing, and sure the little changes should be DOM, but in previous projects (big corporations, IE, XSLT), it was easier and fast enough to re-render the whole XSLT transformation than build and maintain a separate JS/DOM code for the updates.
Mic
Any URL not checked for known-good schemes can hide an active URL (`javascript:` or other similar schemes, potentially obfuscated), in `href`, `src`, `dynsrc`, `codebase`, table `background`, style `url()`; active `embed`/`object`/`applet`, style constructs `expression()`, `behaviour`, `-moz-binding`, `@import`; all `onsomething` event handlers; IE `datasrc` data binding; IE `<?import` behaviours that can invoke script; iframes pointing to exploits; meta-refresh; embedding other languages (MathML, SVG) with their own scripting possibilities; markup hiding in fake comments and invalid markup...
bobince
+3  A: 

+1 year ago, we started a new web app, and needed a way to render HTML from JSON data, in the browser.
We wanted it as fast as an XML/XSLT transformation.

Our answer to that was the JS template engine PURE.

Unlike most of the JS templating libs around, it keeps the HTML untouched(no strange tags at all) and except a few notations, it doesn't bring a new language to learn, only JS and HTML.

The way I use it:

  • Build the static HTML directly in the page
  • Then add the JS logic step by step, and the HTML becomes alive progressively
  • Once you get used to it, both HTML and JS can have a safe separate development life, and can be split between a designer and a JS developer job
Mic