8 ms·
Laconic: A Sane Method of Generating DOM Content in JavaScript
- tzm 14y agoClever DSL. Thanks for sharing.
- peterhunt 14y agoI did something similar here: https://github.com/petehunt/htmldry/blob/master/demos/eventsite/demo.coffee https://github.com/petehunt/htmldry/blob/master/demos/events... It's a little more HAML-inspired though.
- mkmcdonald 14y agoYour API will explode violently in IE < 8 || Quirks. This is because of gratuitous use of `setAttribute` along with `Array.prototype.slice.call` (dirty hack)[0]. IE < 8 || Quirks already treats HTML attributes and DOM properties identically[1], so really, DOM properties are preferred. More standards-compliant environments will reflect the property value in the corresponding attribute value (if possible). Using `Object.prototype.toString.call` is also a pretty dirty hack, especially to detect an "array". I think `typeof obj === "object" && obj.length` would suffice, even if certain false positives like string objects leak through. [0]: http://i.imgur.com/RNBYd.png http://i.imgur.com/RNBYd.png [1]: http://msdn.microsoft.com/en-us/library/dd347148(v=VS.85).aspx http://msdn.microsoft.com/en-us/library/dd347148(v=VS.85).as...
- deleted 14y ago[deleted]
- Joeri 14y agoThe "Object.prototype.toString.call" solution is guaranteed to work according to ECMA-262, and will only return true for a real Array instance (not something masquerading as an Array): Object.prototype.toString ( ) When the toString method is called, the following steps are taken: 1. If the this value is undefined, return "[object Undefined]". 2. If the this value is null, return "[object Null]". 3. Let O be the result of calling ToObject passing the this value as the argument. 4. Let class be the value of the [[Class]] internal property of O. 5. Return the String value that is the result of concatenating the three Strings "[object ", class, and "]".
- mkmcdonald 14y agoThat may be, but it's poison for host objects. In older IE and Opera builds, `"[object Object]"` comes up often, even for host methods. This is because there is no defined standard for `toString` results of host objects.
- maratd 14y agoI simply generate global functions corresponding to tags, so my stuff looks like this: div(span('hello world')).inject(document.body); Very simple to do and even simpler to use.
- joestelmach 14y agoMany would frown upon polluting the global name space with functions corresponding to all known HTML tags.
- tikhonj 14y agoIf you end up wrapping your code in an immediately called lambda anyhow I'm sure it would be fine.
- mistercow 14y agoSort of, but there are some tags you probably don't want to pollute your own top-level namespace with, like a, b, i, object, p, q, and s. There's at least one tag (var) which is not allowed as an identifier on its own.
- WiseWeasel 14y agoI think 'a' and 'p' are the only ones among those you'd actually want. I could probably live with with those limitations.
- WiseWeasel 14y agoNow that I think about it, that might break a few sortFunction(a,b) {//do stuff with a and b} type functions of mine...
- mistercow 14y agoNo, it won't break them; it will just make them confusing to read. The scope of the function arguments would be more local, so they would hide the declarations further up the scope chain. What's more of a problem is if you have something like this: https://gist.github.com/2499913 https://gist.github.com/2499913 The problem is that the "var p" in the for loop will be hoisted to the top of the scope, and so when you call p() in the first line, it will actually be undefined.
- firefoxman1 14y agoThis is really neat. The coolest part is being able to register your own "tags" which take any arguments you want. The problem I see is that this only works for "all known HTML tags." If you want to use custom tags, like <template> (I believe that's what meteor uses), this won't cut it since it uses $.el.tagname syntax, every tag has to be loaded into the $.el object. How about a very similar, more jQuery-like syntax instead: $.el('template', [ $.el('div', {'class' : 'foo'}, [ //other children here //so basically, the last arg is always an array of children ] ]);
- joestelmach 14y agoThough I did a poor job at documenting it, $.el is actually a function that accepts a tag name as the first parameter. The following two snippets are equivalent: $.el.div({className : 'foo'}); $.el('div', {className : 'foo'});
- firefoxman1 14y agoThat's awesome! Yeah I see it now in the source's comments. Thanks for pointing that out; I'm sold.
- aneth 14y agoThis is pretty, but unfortunately the only performant way to generate dom elements in javascript is with HTML. HTML parsing is orders of magnitude faster in most browsers. How about a library like this to generate a string of HTML instead of dom elements?
- mistercow 14y agoSeems to me like an implementation detail that shouldn't have to affect the interface at all.
- firefoxman1 14y agoLike a template engine?
- aneth 14y agoPerhaps like some template engine, but not like any I know of.
- joestelmach 14y agoWhile I don't entirely agree with your first statement, you could just grab the outerHTML instead of appending the element directly to the DOM: $.el.div($.el.span()).outerHTML
- aneth 14y agoSeems like a reasonable solution. My first statement was certainly true in the previous generation of browsers, including IE 7. I'm not sure about more modern browsers. What basis do you have for disagreeing? Refer to: http://www.quirksmode.org/dom/innerhtml.html http://www.quirksmode.org/dom/innerhtml.html
- joestelmach 14y agoI'm only disagreeing with the use of the word 'performant', and the popular viewpoint that any solution that isn't as fast as possible can't be labeled as such.
- stephenhandley 14y agoi don't understand the appeal of this when there's tons of client side js templating options (handlebars, jade, haml-js,...) that result in far more readable code than a $.el. prefixathon
- joestelmach 14y agoWhile I agree the $.el prefix is annoying, I don't believe it has a negative effect on readability. For me, templates are just another level of unneccesary indirection.
- anonymous_mouse 14y agoThat looks ugly to me. I much prefer CoffeeScript, because plain JS makes me mad, and CoffeeKup (http://coffeekup.org/ http://coffeekup.org/) for generating DOM content.
- Stratoscope 14y agoJust for fun, here's my version from 2006: http://mg.to/2006/02/27/easy-dom-creation-for-jquery-and-prototype http://mg.to/2006/02/27/easy-dom-creation-for-jquery-and-pro... It's based on Bob Ippolito's version from 2005. :-) The comments on the post have a few other interesting implementations that others contributed. At the time I got pretty excited about this idea, but I abandoned it after a while for performance reasons. I was building large DOM structures and it was really slow. I knew that innerHTML was faster, so I tried keeping the same syntax and generating HTML from it instead of DOM insertions - and it was almost as slow that way! Then I realized that it was just the sheer amount of JavaScript code being run that was slowing it down. I changed my code to build HTML strings with array pushes and a join at the end and then innerHTML to insert, and it was much faster. Of course, JavaScript has gotten a lot faster since then (at least in new browsers!), so the more code-intensive techniques may be more practical now.
- joestelmach 14y agoThanks for sharing. JavaScript has come a long way, even from 2006, yet most developers still have the mindset that this sort of thing can't perform well. What we're left with are solutions that are more complex, and perform similarly for most applications.
- pault 14y agoThis is fine for small, one-person projects, but if you generate DOM content in your JS views it will come back to bite you in the ass once you hit a certain size. The first time you need to bring in a designer, or integrate a static mockup from a designer, you'll be wishing you used a template engine. You wouldn't embed database queries into your view controllers, so why would you couple your html to your javascript?
- joestelmach 14y agoThanks for the tip, but I've had much success using this method on teams of 5+ developers and a full-time designer.
- pault 14y agoObviously you should do whatever works for your team, and I'm not commenting on the quality or necessity of your framework. In my opinion, it's just much easier to edit well formatted markup, verbose as it may be, than wading through a forest of $el and appendTo and such. Not to mention, hiring a talented visual designer that knows html & css is much easier than finding one that knows their way around a client-side MVC framework. Unicorns and all that. To each his own.
- fauigerzigerk 14y agoBecause database queries and views belong to different logical layers whilst JavaScript and HTML are just different technologies that may be used for things on the same logical layer. But I think your point about designers is a valid one for many projects.
- jiyinyiyong 14y agoIt's really boring to write appendChild again and again.. Here's my idea(as a begginer), just converts json(in CoffeeScript) to html string. http://docview.cnodejs.net/projects/json2page/show.html?html http://docview.cnodejs.net/projects/json2page/show.html?html
- robmueller 14y agoSimilar approach to what we took. http://blog.fastmail.fm/2012/02/20/building-the-new-ajax-mail-ui-part-2-better-than-templates-building-highly-dynamic-web-pages/ http://blog.fastmail.fm/2012/02/20/building-the-new-ajax-mai... Used the CSS syntax to easily set class/id on a newly created tag. Benchmarks included to show it's just as fast as innerHTML on modern browsers.
- maxbrunsfeld 14y agoAnother very cool take on this idea: https://github.com/nathansobo/space-pen https://github.com/nathansobo/space-pen
- deleted 14y ago[deleted]
- phleet 14y agoSee also jquery-haml: https://github.com/creationix/jquery-haml https://github.com/creationix/jquery-haml
- DanielRibeiro 14y agoEven more laconic: http://coffeekup.org/ http://coffeekup.org/
- lucian1900 14y agoWe use this for a mobile app and it's very nice. Haven't run into any issues, at least so far.
- ehsanu1 14y agoAnd yet more laconic: http://code.google.com/p/zen-coding/ http://code.google.com/p/zen-coding/
- ars 14y agoIn what way is this better than writing HTML? And just using innerHTML, outerHTML etc? It's a serious question. What benefit is there to doing this? The only thing that came to mind is now you have the dom node so you can bind events to it. But you're not going to be doing that everywhere. So why make things more complicated?
- deleted 14y ago[deleted]
- strayerror 14y agoSimilar library with namespace support (SVG, MathML): https://github.com/mal/watson https://github.com/mal/watson
- insin 14y agoHere's another one I did: https://github.com/insin/DOMBuilder/ https://github.com/insin/DOMBuilder/ It also allows you to generate HTML strings from the same code and create templates, with template inheritance, using the same sort of syntax.
- DavidAbrams 14y agoDoes anyone have a recommendation for a not-too-bloated template engine? I'm going to be building a small-business Web site to display products from a MySQL database and possibly offer shopping-cart functionality. Thanks!
- DavidAbrams 14y agoOh well. Guess not.