20 comments

[ 3.3 ms ] story [ 60.1 ms ] thread
This is fine for scalar binding of simple values - a property mapping to a value - but what about vector binding, where you have a list of items, and need the UI to reflect insertions, deletions and sorts?

And what about enabled state, display state, or more complicated binding that changes the structure of a DOM node - e.g. converting the icon on a button to fa-cirle-o-notch while an asynchronous operation is occurring?

It might be fine for extremely simple needs, but if you're going with a UI which dynamically reflects your model and application state, you should IMO go all the way. When done right (which usually means as functional, in the programming sense, as possible), a binding setup greatly reduces the amount of thinking you need to do to keep the UI in sync.

(I'm probably missing something and the library is more capable than it looks; on a closer examination, I do see it doing some kind of vector binding, but I don't think it can do e.g. heterogeneous elements, where the HTML per element differs depending on the model.)

I think you're correct about its intended use case being different. I used Twitter's Mustache compiler, Hogan.js, in a similar fashion for a tiny app once.

Though I suppose I should highlight the latter being client-side templating, as opposed to one-way data binding.

author here - getting iteration and nesting to work was the hardest part, and I don't think the basic example on the homepage illustrates this too well.

the way it works is that every value gets cast into an array for rendering purposes if it isn't already. so in case of an array of objects, you don't need to explicitly define that you expect an array, it'll just render `n` objects with nested bindings.

to give an example, on the homepage there's an array that is rendered, `["Tall", "Grande", "Venti"]`. if a new array is set, for example, `["Tall", "Grande"]` (without "Venti"), it will re-render based on if the values at the indices changed, so in this case it would just remove the dom node for "Venti".

another cool thing is that with the mount function, you can either return nothing so that the node that was specified will be appended, or return a completely different node based on the value, which enables heterogeneous elements in a list. the mount function also gives you an opportunity to mutate a node in other ways than just setting the text/value/checked/whatever, such as setting a classname i.e. `node.className = "fa fa-hourglass"`. then there's the unmount function but 99% of the time won't be needed because dom nodes that aren't in the live tree and don't have a reference will just get GC'd.

it should be entirely possible to build a web app with Simulacra.js using a single bound object, a single template, and describing all possible bindings in one go. it's up to the developer to add whatever convoluted architectures are hip at the moment (stores, reducers, actions, what have you).

I've been looking for something like this. This cleanly solves the basic (majority) case and doesn't try to boil the ocean. It looks like it would be easy to build a higher-level API with more features on top of this, which is great. Nice work. Also kudos for documenting the shims in lieu of bundling them.
These benchmarks are tough to reproduce (for all libs). Mithril's instructions say, "To run an execution time test on this page, run the profiler from your browser's developer tools and measure the running time of a page refresh. (Lower is better)"

There are a lot of variables that affect a full page refresh...caching, etc. I could not get those ms numbers in any scenario, not sure what I should be looking at.

Would be more useful to stress-test the lib by implementing dbmonster [1] and speedtest* [2]. These perf tests have the benefit of being good visual comparisons and also stressing the browser's GC to evaluate how efficient a lib is at minimizing overall mem usage and reducing jank.

I've been working on a DOM view layer lib [3] that does exceptionally well in both of those. (more demos and docs coming soon).

EDIT: added domvm dbmonster demo [4]

*speedtest is ultra-slow in FF for all libs, the winner is surprisingly innerHTML. still need to narrow down the cause to open an FF bug.

[1] http://joelrich.github.io/fastest-dbmonster/

[2] http://rawgit.com/crysalead-js/dom-layer/master/examples/spe...

[3] https://github.com/leeoniya/domvm

[4] http://leeoniya.github.io/domvm/test/bench/dbmonster/

I agree that it would be more informative to stress-test using a more real-world use case, I was just in a hurry and used the render benchmark from Mithril.js.

however I think that any benchmark may be skewed to favor a particular implementation. for example, Simulacra.js doesn't batch updates and render asynchronously, it's purely synchronous, so one could set up an artificial benchmark to thrash the DOM by setting different values over and over again in the same tick.

also I haven't yet committed the benchmark I used in git, will do later so that people can reproduce it.

this is correct, and Mithril's docs also point this out. domvm uses rAF internally to debounce changes but it can be toggled off (and IS toggled off [1]) for perf tests to make it 100% synchronous as well (via domvm.useRaf = false).

would be very interested to see Simulacra's perf in those, when ready. thanks!

[1] https://github.com/leeoniya/domvm/blob/master/test/bench/dbm...

Interesting project and it's nice to see work done on something compact and minimalist.

But I don't like that CSS classes are used to bind data. I know other libraries do this too but I don't think it's a good idea.

CSS classes exist for styling purposes. It's hard enough as it is to keep track of classes, where they're used, how they're used etc... on anything but the most trivial project. Using CSS classes for both style and data binding would result in a maintenance nightmare, IMO.

Why not use something like: <div class="some-style" data-binding="product-name">

It's perfectly legit HTML and maintains separation of concerns.

someone posted a similar criticism on reddit: https://www.reddit.com/r/javascript/comments/3tqw5l/simulacr...

it may have been a poor choice to use class names in the example, but I just wanted to demonstrate that the library is not coupled to a certain way of selecting dom nodes. it's entirely possible to use $('[data-binding="my-thing"]'), but not necessary at all.

I've gone back and forth on this with a previous coworker before.

My opinion on it now is: there's two common general ways to use css. One way is as a style class, which is something you'd apply in multiple places around your project (like `.error` setting font colors to red, for example). The other way is to markup specific content so that you can apply specific styles to it - for instance, pixel pushing a header to fit exactly where you think it should in this one instance (perhaps to align an upvote button with a username, or something).

The latter way really seems to just markup dom nodes purely for the sake of identifying them within their structure (I might use BEM or rscss especially for these).

The way I structure my css in projects follows from this - I extract common styles and pepper them throughout my app where needed (but they are never referenced in any js/$ selectors). These are intended to cascade.

And then I will scope my more specific css under a selector (using sass, or cssnext or whatever) to avoid polluting the global scope:

  .some-view {
    .header { ... }
    .note { ... }
    .icon { ... }
 }

In the case of these nested selectors, they are more identifying tags for the content of the node, than they are declarations of a specific style. These are not intended to cascade.

So even though css classes "exist for styling purposes" I think they have two paradigms for use. One for marking up content for a general application of a style and another for marking a node to be given special treatment.

And taking that approach, I argue it's fair to use the same selectors for js as well as css.

Besides, in practice, you're going to realize you're just adding the same class name appended with `js-` everywhere `<div class='error error-box js-error-box'></div>` when you're using that `error-box` really only to mark the node for use.

Though I'd be curious to hear more about why you think this:

>Using CSS classes for both style and data binding would result in a maintenance nightmare, IMO.

If you always use something like 'data-bind' for binding and keep classes solely for CSS it's easier to maintain simply because you know 'what classes you can delete' without having to look in two places (CSS and JS) to see what will be affected as a result.
This looks pretty interesting. It does require the structure of the HTML to be very similar to the object, though. And I'm not thrilled that is uses the class name for a DOM node in the key/value pair. Why not define some "data-" attribute to read from?

EDIT: Looks like I posted without reading all of the comments in regards to the class name thing. I see some other people have mentioned it as well. It also looks like the author states that this isn't a hard requirement. I guess that would solve that problem at least.

>It does require the structure of the HTML to be very similar to the object

that's true, the basic nesting of objects has to be preserved in the html but i don't know how it could be possible otherwise. it just wouldn't make sense to bind a nested key to a dom node contained in an ancestor object but not itself.

I've been doing database-backed web apps using MVC frameworks for so many years, that it's hard for me to wrap my head around the front-end javascript frameworks. This one seems simple enough that I might be able to understand it though...

Can you clarify for me, though, how exactly to utilize this in my code? I see the `require` statements, which I'm guessing means you assume the use of browserify or some module loader (or ES6)... but would it be possible to use this just as a plain old javascript file via a `<script src="whatever"></script>` tag?

Also, are there any more fleshed-out examples of how to use this for a realistic app?

Thanks!

when installing modules from npm, it's customary to use commonjs and `require` them. or you could simply download the built version, include it as a script tag and use the global `window.simulacra`. I have yet to build a complex app using my own lib, but it's one of the main reasons why I wrote it.
(comment deleted)
Ah, gotcha. I didn't notice the download button on your website at first. (You might want to remove the faded style from it -- it looks disabled to me and I think that's why I glossed over it.)

Thank you!