7 ms·
Hamlet – Simple and powerful reactive templating
- bradgessler 12y agoWe use hamlc and Backbone.js in our stack. This lib looks like it will simplify a lot of that. I have a few questions: 1. Its interesting to see JS events specified in the template (e.g. `%a(onclick=@doSomething)`). Is there a way to specify that in the JS/model? 2. Does "Observable" mean that the value is updated when the model changes, when the DOM changes, or both? Could all of the attributes of the object passed into the template be observable by default or would that incur a significant performance penalty?
- Yahivin 12y agoFor point one, it is specified in the model. @doSomething would invoke the model's doSomething function. The template just names it. As to point two, observable provides a bi-directional binding so that changes to the value are reflected in the DOM and changes in the DOM are reflected in the model. The observable interface is essentially a jQuery style getter/setter method that allows for observers to be notified of changes.
- klibertp 12y agoWhen is the DOM updated? Are the changes performed as soon as they are observed or are they queued? Does Hamlet implement some kind of "virtual DOM" for diffing or does it sync DOM and model directly? Looks very nice, just this weekend I looked at some frontend frameworks, including Vue, Mithrill, Ractive and React and found some issues with them all. Hamlet would fit my use case very well, I think. One thing I'd like is more technical details on the main page - not how it "looks like" compared to other frameworks, but how it does its thing (compared to other frameworks).
- rich_harris 12y agoThanks for trying Ractive (I'm on the core team). If you don't mind, I'd be interested in knowing what issues you came up against with those frameworks that you listed?
- Yahivin 12y agoThe current implementation performs changes immediately. There is no virtual DOM, as soon as a change occurs the model is update and vice versa. The Observable component invokes the callback to all listeners immediately when its value is changed. I find this makes testing and debugging somewhat easier than async callbacks or nextTick.
- bradgessler 12y agoHow does observable wrap values? I see a few things: list = Observable [] list.push 'blah' and isOrange = Observable false isOrange = true // This obviously doesn't work this way... Do you poll the value? Or do you check the type of the value and wrap/proxy methods that would normally change the value?
- Yahivin 12y agoWhen Observable is declared with a type (especially an array) it sets up some wrapped methods to simplify working with it. The wrappers also set up automatic dependency resolution so you can do cool things like: list = Observable [] reversed = Observable -> list.map reverse list.push 'blah' reversed() # => ['halb'] There's no polling, the observable notifies all observers immediately when the value changes.
- bradgessler 12y agoWhat about simple types, like the `false` value example above? Is there a `set` and `get` method?
- mdiebolt 12y agoYou'd use a jQuery style setter. isOrange(false)
- peterhunt 12y agoWhat issues did you find with React?
- Dorian-Marie 12y agoI see you can also use `%button(click=@hello) Hello!` in the example page: http://hamlet.coffee/garden/ http://hamlet.coffee/garden/
- Yahivin 12y agoThat's correct. Both styles of event names are supported!
- pbiggar 12y agoWe use hamlc and knockout: this seems like a wonderful improvement. If only we weren't 80% of the way to cljs+om.
- zeekay 12y agoWould be extremely appealing if it borrowed more inspiration from Jade than Haml.
- Yahivin 12y agoI actually agree! I started with haml because it's what I knew best at the time. The parser is separate from the compiler and the runtime, so it should be simple enough to add a jadelet, anglet, or any other simple style of adapter. If there is a lot of interest in a jade focused style or haml is a turn off for many people then it will become a priority for us.
- arxpoetica 12y agoyes plz.
- lobo_tuerto 12y agoYou should checkout slim too, it's just a better haml. http://slim-lang.com/ http://slim-lang.com/
- smrtinsert 12y agoReactivity is becoming an imperative. The browser of the future will let us code in a reactive language instead of forcing non reactive html or js on us. I'd love to see something simple for other languages and platforms as well. I love that it seems to not be tied to node out of the box as well.
- Yahivin 12y agoYeah, it's only taken us 50 years :) One of our goals was for Hamlet to be suitable for really small and simple web apps, without any big framework or ecosystem. There's still a lot of work for us to do on the ease of getting started (both with or without node) so if you run into trouble or have any comments let us know.
- smrtinsert 12y agoWill do, and great job.
- chriswarbo 12y agoAn unfortunate choice of name. When I saw the title, I thought it was on about https://hackage.haskell.org/package/hamlet https://hackage.haskell.org/package/hamlet
- Yahivin 12y agoIt's a popular play!
- dllthomas 12y agoAnd contains H, T, M, and L.
- cstrahan 12y agoThat was my thought, too. Rather unfortunate.
- progrium 12y agoThey should have took my naming suggestion and called it Jon Hamm.
- Yahivin 12y agoIt was a close second, but I think there's the same problem of someone already being named that.
- EGreg 12y agoWhen I saw the title, I thought it was about a Shakespeare play. That's already taken!
- dllthomas 12y agoParticularly in so related a space.
- Tyr42 12y agoOh, I thought this was the already existing Hamlet language. Of which there are at least two. http://www.yesodweb.com/book/shakespearean-templates http://www.yesodweb.com/book/shakespearean-templates https://github.com/gregwebs/hamlet.rb https://github.com/gregwebs/hamlet.rb It does look pretty cool though.
- Grothendieck 12y agoActually, at least one: the Ruby version is just a port from Haskell and has the same syntax.
- Tyr42 12y agoOh, shoot, I googled for the Haskell one, and saw the other one on the way. I should have read about two more lines, and I would have got it. In my defence, I always thought the main feature of Hamlet is the static checking of everything, and solving the escaping problem (at compile time!), so I didn't even entertain the idea that someone would port it to Ruby.
- jonahx 12y ago@Yahivin, I'd love to hear your thoughts on Mithril. Have you used it?
- Yahivin 12y agoI hadn't seen Mithrill before, but from checking it out now it looks like it has a lot in common: small runtime, trying to be as close to plain JS and DOM as possible, and safety by default. I'm not sure if it provides as much magic as Hamlet's auto-dependencies and template syntax, but those do have costs and tradeoffs. I would like to see an interactive demo on the site so I could get to know it better by messing around.
- bmcmaste 12y agoLooks really interesting. Any plans for a Rails Gem?
- Yahivin 12y agoYes, we plan to create or assist the creation of drop in solutions for Rails, Sinatra, and popular node frameworks, priority based on interest, volunteers, and whoever demands it the loudest.
- cfitzhugh 12y agoI've really enjoyed ractive. Simple to learn, with mustaches, and it has worked really well for our project. No extra compile steps. Figured I'd share since I see alot of buzz around React and other things, and preferred ractive.js when I researched it a little bit ago.
- Yahivin 12y agoWow, I hadn't heard of Ractive before. It looks quite similar in approach and also really cool.
- mquandalle 12y agoThis looks to be a great declarative/reactive template engine. I've been working mostly with the Meteor Blaze template engine the last few months. Both of them use a "normal" template language for writing views and (potentially) let you choose if you prefer writing your templates in Handlebars, Jade, or Haml [0], which I find far more easy to use than React JSX format. I think Blaze beats Hamlet on the runtime rendering engine. First, Blaze does not require to set a root element in a template, which could be a source of bugs with Hamlet because for instance the `each` child is a template, here is a snippet of problematic example from the Hamlet README: - each @items, -> .first .second This works perfectly fine in Blaze. IIRC Blaze uses comments node on the DOM that are never rendered in browsers in order to define some "domrange" that keep track of n children in a single parent group. The second runtime issue in Hamlet appears when a third-party library directly modifies the DOM, without telling the template engine. Basically the modification will be erased on the next template redraw which make this system incompatible with all jQuery plugins for instance. Blaze has "fined grained DOM updates" which mean that the modification of a single element in a template does not require to touch any other node in the DOM. For instance if you have a each loop of inputs, and the user start to enter some data in one input field, and for some reason the template is redrawn the text will stay in the input with Blaze, but will be erased with Hamlet. Blaze also support reactive SVG (I'm not sure if Hamlet supports it but I haven't seen any particular mention in the code). I think all of these features can be implemented in Hamlet drawing on Blaze and ReactJS runtimes. Nevertheless I find the Javascript model declaration cleaner in Hamlet than in Blaze or Backbone or React. The only thing I'm not sure about is writing the js events in the template and not in the model, I actually like having all events of a given template in a single place but I don't have strong opinion on this. [0]: Meteor support Spacebars (which is quite similar to Handlebars) by default https://github.com/meteor/meteor/blob/devel/packages/spacebars/README.md https://github.com/meteor/meteor/blob/devel/packages/spaceba..., and there is also a package for jade https://github.com/mquandalle/meteor-jade https://github.com/mquandalle/meteor-jade (disclaimer: I'm the author). It also seems that it wouldn't be difficult to support other languages than Haml for Hamlet.
- Yahivin 12y agoThat issue about requiring a root item should be solvable in the future, it's just the current implementation that has limitations. I'm building up the test suite to specify the behavior and hope to have it working soon. For the most part jQuery plugins should work fine with Hamlet, so long as one remembers to update the data in the model rather than arbitrarily throughout the DOM. It can be a moderate mental shift to go from jQuery style "The DOM is the data" to the newer Backbone, Knockout, React, Angular, etc style of "The model is the data" and may not be right for all applications. Thanks for the comment I'll take a look at Meteor Blaze and see what cool tricks it has :)
- coherentpony 12y agoOh wow, people are actually using these new TLDs.
- mdiebolt 12y agoIt's pretty awesome to be able to host CoffeeScript OSS projects on a .coffee TLD
- Smudge 12y agoGot this JS alert: "This website abuses rawgit.com. You should complain to its owner."
- peterhunt 12y ago> Avoid working with over-engineered frameworks without sacrificing a great interactive experience This is a pretty lame claim seeing as text fields are busted in Hamlet. [1] This is another example of a "lightweight" library that hasn't hit any of the hard problems yet. It's fine if you make this your personal project to learn from, but trying to convince people to bet their projects on unproven technology is pretty disingenuous. [1] Inserting characters does not work in the second example at http://hamlet.coffee/garden/ http://hamlet.coffee/garden/
- Yahivin 12y agoA technology becomes proven through use. What browser and OS are you using? The examples have worked in our testing environments of Chrome, FF, IE9+, Safari, and Opera.
- CanSpice 12y agoAll of those examples work for me with Chrome 35. One thing I would love on HN is the reluctance to say something is "lame" because one example doesn't work for one person on one browser. Instead of being dismissive, why not be constructive? Or if you can't even do that, just don't post?
- peterhunt 12y agoIf you look at my posting history you'll see that I tend to agree with your sentiment. Too much negativity on HN and I combat it where I can. But "lightweight" JS fetishism at the expense of correctness (and the arrogance that comes with it!) is an epidemic in the frontend web business today. I think it's important to highlight this when it happens so we can stop making crappy web apps and start to actually deliver reasonable experiences when compared to native. Also here is a video of the bug: http://www.petehunt.net/hamlet.mov http://www.petehunt.net/hamlet.mov
- Yahivin 12y agoHi Pete, I can't get the video to work on my machine. When opening it with the default video player I get: An error occurred This file contains no playable streams. System info: ♥ uname -a Linux yolobookjr 3.8.0-35-generic #50-Ubuntu SMP Tue Dec 3 01:24:59 UTC 2013 x86_64 x86_64 x86_64 GNU/Linux Looks like a lot of software still has room to improve. :)
- chenglou 12y agoComparing your CoffeeScript example against a vanilla JS React example seems cheap. here's the front page React example in CS: converter = new Showdown.converter() MarkdownEditor = React.createClass getInitialState: () -> value: 'Type some *markdown* here!' handleChange: (e) -> @setState(value: e.target.value) render: () -> d = React.DOM d.div( d.h3(null, 'Input'), d.textarea(onChange: @handleChange, value: @state.value), d.h3(null, 'Output'), d.div(dangerouslySetInnerHTML: __html: converter.makeHtml(@state.value)) ) React.renderComponent MarkdownEditor(), document.querySelector('.container') Showing a LOC comparison (and not even from the same dialect of a language) isn't a good proof for what you're trying to demonstrate. Clarity, simplicity, and debuggability all count. Removing a few extra lines of (non-boilerplate) code compared to React doesn't make the library simpler to work with.
- mdiebolt 12y agoI thought about that when constructing the demo but opted to use the JSX / plain JavaScript version because that's what's displayed on the React homepage. We have a strong preference for Haml and CoffeeScript dialects so that's how we present our demos. I built jsfiddles based on how each framework presented their own product.
- chenglou 12y agoIt is indeed displayed on the front page, in vanilla JS, but that doesn't change the fact that it's not a very accurate comparison, providing that the point you're trying to prove is LOC. The React version also showcased attributes such as `className`, which Hamlet didn't. Nothing against CoffeeScript; just picking on the comparison itself. Also, React is a view library, not a full-stack framework. The fact that it's put on the same level as other real JS frameworks is an acknowledgment of its paradigm's power and usefulness. So I guess people viewing it as a framework is a misleading but very telling phenomenon. That being said, good luck with the project!
- krick 12y agoI'm more intrigued by the domain name. Why there even exists 1st level domain "coffee"?
- toisanji 12y agoits too bad this is made for coffescript, i would have liked to see it for regular javascript.
- Yahivin 12y agoIt does work with regular JS though we present our examples in CoffeeScript.
- notastartup 12y agoWhat's wrong with just using jQuery? what's the rational for using a reactive solution?
- Yahivin 12y agoSay you're building a color picker with three text fields for R, G, B, and a swatch that displays the resulting color. You could do it in jQuery, but plumbing all the update code for each input would be kind of a chore. If you get a new source of input (say from the network) you'd have to remember to resync everything. To keep it simple you'd probably have to respond to `something changed` -> `update everything`. Reactive templates would only update the elements dependent on that change. With a reactive solution you make a model that contains observable RGB values and a function to compute the final color. Once you bind that model to your view everything stays in sync like magic.