Nick Sabalausky wrote: > (but I've done worse - I once tried to build HTML > buy manually adding nodes to an XML DOM...it seemed like a good idea > until I actually started doing it).
This is actually one of the methods I've been using in my D web apps throughout the year. It's not that bad if you extend DOM with D. Compare: auto table = cast(Table) document.getElementById("mytable"); assert(table !is null); foreach(item; myArray) { table.appendRow(th(item.id), new Link(item.name, "myappurl", ["mode": "view-item-details", "id" : to!string(item.id)), item.owner, item.comments.brief); } With the godawful equivalent in Javascript. The DOM extensions also make multi-page forms trivial: auto form = cast(Form) document.getElementById("my-form"); assert(form !is null); foreach(k, v; cgi.post) form.setValue(k, v); That adds all the data POSTed in to the form. form.setValue is smart enough to work with existing fields, or add new ones as hidden inputs. (Existing fields including check boxes, selects, radio groups, etc. It Just Works with just about any html.) I used to dread having to make edit capabilities. <input type="text" name="whatever" value="<?= $myVal" /> And setting myVal and repeating over and over and over and over and over and over and over again. Then the hell: <input type="checkbox" name="sucky" <?php if(isset($_POST['sucky'])) echo 'checked="checked"; else echo ''; ?> /> Then hell isn't strong enough of a word. <select><option value="1" <?= ($value == 1) ? "selected" : ""?>>blah</option> REPEAT REPEAT REPEAT </select> Now, I can just use the two line loop and it works in all cases. Another huge benefit of the extended dom is: h2.innerText = myTitle; The innerText property, a MS extension in Javascript, automatically escapes the string for safe output (like all DOM methods, except for innerHTML itself) and is easy to use. No: h2.appendChild(document.createTextNode(myTitle)); Ugh. Anyway with a few little DOM extensions, this actually becomes quite usable. It isn't always perfect, so my code also has variables in the template: {$myVar} in the html and in the D, document.vars["myVar"] = to!string(whatever); Naturally, the template variables are all automatically escaped. The last thing I added are a could special html tags and attributes. <include file="blah" /> to share template files. <table class="striped"> <ul class="striped"> etc.etc. Elements with the striped class get every other relevant child marked with class="odd", so I can add the color or whatever in the css file: table.striped .odd { background-color: teal; color: red !important; } (lol colors) The program is smart enough to mark only the correct elements as .odd. If it is ul.striped, it gets every other immediate li child. For a table, it goes for table > tbody > tr.odd. (This reminds me: document.getElementsBySelector() is a godsend extension too.) But, generally, what other templates solve with loops or recursion, I try to solve with classes and css. We've been live for 8 months now, and I haven't felt the need to add looping to my template. The closest I have is: <list from="collection" format="html output format for each element" /> But even this very rarely actually specifies the format: the context-aware code does the right thing in most situations, and when it doesn't, it tends to be a one or two line DOM fixup anyway. "Doesn't this violate Model and View separation???" No, I don't think so. The HTML at this level is extremely minimal, if any is specified in the code at all. It only decorates the semantics of the data, which isn't really view related. Give it just enough markup so the stylesheet can take over without needing to pull your hair out. I wonder how many of the HTML template solutions were made by people who don't understand CSS. CSS can't really do all the work by itself, so you keep the html framework around it, but when it comes down to styling individual data elements, CSS is really very good at it. If you are changing the html to change your view at that level, I'd say you're doing it wrong, template or no template.