
Show HN: Simulacra.js – one-way data binding for web applications - daliwali
https://0x8890.github.io/simulacra/
======
barrkel
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.)

~~~
daliwali
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).

------
leeoniya
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/](http://joelrich.github.io/fastest-dbmonster/)

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

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

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

~~~
daliwali
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.

~~~
leeoniya
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...](https://github.com/leeoniya/domvm/blob/master/test/bench/dbmonster/index.html#L21)

~~~
daliwali
I added a benchmark folder:
[https://github.com/0x8890/simulacra/tree/master/benchmark](https://github.com/0x8890/simulacra/tree/master/benchmark)

cheers!

------
teleclimber
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.

~~~
gravity13
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.

~~~
nilliams
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.

------
matthewtoast
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.

------
jordanlev
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!

~~~
daliwali
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.

~~~
jordanlev
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!

------
marksteve
I love it! This is going to be my goto library for lightweight ui from now on.
[https://github.com/marksteve/todo-
simulacra](https://github.com/marksteve/todo-simulacra)

------
Dru89
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.

~~~
daliwali
>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.

------
leeoniya
reminds me of

[http://beebole.com/pure/](http://beebole.com/pure/)

