Presenting a new ViewModel package

Hey, thanks for your interest – and great questions. Keep them coming.

Generally speaking, the reason I like using Blaze instead of jQuery, is that elements (or attributes etc.) are completely ready when they are rendered. They don’t exist before, at all.

Flickering

… so flickering doesn’t become a problem.

Alternative syntax

I agree that using a string with a colon in it looks more artificial than a keyword argument.

Actually, I realize that I’ve been inconsistent in the way that bindings can have a detached option, but you can’t omit the property name from the bind expression without the library failing. I’ve corrected this for the next version.

Here’s the problem with using keyword arguments as bind expressions, though:

Every keyword argument would designate a binding, so we would lose the possibility of passing actual keyword arguments to the bindings.

This is a feature we can’t do without, since it is the only way to pass dynamic data to a binding (not just a string argument inside the bind expression). Which happens to be one of the major advantages of this package :smile:

Classes

I don’t want to parse objects inside bind expression strings. It’s too complex. Here’s my suggestion for having a class binding:

<div {{bind 'class' classes=classes}}></div>
// viewmodel
{
  red: true,
  classes: function () {
    return { red: this.red() };
  }
}

I’ll add this binding to the set and push version 0.5.6.

Oh, and about passing the key to set – I don’t want to do that, because I want to make it impossible to write back to the property inside set, since this would create an infinite loop.

You shouldn’t need the key inside set – the key is arbitrary. You shouldn’t write a binding in a way that needs to know the key (i.e. the property name).

If you really, really need the key inside set, it will be the first item in the args array. Don’t do it, though :wink:

Thanks for your response. I’ll just keep the old order here :slight_smile:

Flickering

It actually becomes a problem, when trying to write bindings, which initially hide an element. However, this seems to be a problem not specific to this library or Meteor, but jQuery and browser behavior. Looks like I need to work around by hiding the element using CSS at page load.

Alternative Syntax

I just noticed that it’s not possible to add more than one binding at once. Even if you disagree with the following, my vote goes for multiple bindings, separated by semicolon.

What I’m doing a lot at the moment is something like data-bind: click: _submit, class: { disabled: !_isValid }. So what I was hoping for is {{bind value=name disabled='!validName'}}. I don’t know where I’d need dynamic data for binding; and if I did, what’s wrong with using this[args[0]]? Should be dynamic as well.

Classes

Thanks for your suggestion, but we’d have to write a function for every element on the page where we want to use dynamic classes, instead of just adding that “logic” directly to the element.

Flickering

My opinion is, basically, that you shouldn’t use jQuery to hide an element after render. If you want it to be hidden instead of unrendered, because of some jQuery plugin logic, make sure it gets rendered with the correct class and/or settings.


Alternative syntax

I think I made a good argument about the syntax before, but if having multiple bindings – {{bind 'value: value' 'disabled: disabled'}} – is currently broken, I will fix it right away. EDIT: Fixed

In regard to dynamic data – the args passed to a binding’s set and get are hardcoded as part of the bind expression. They are any space separated strings that come after the colon – with the first item usually being a key. (N.B. before version 0.5.7, the key was omitted from the args array.)

{{bind 'myBinding: arg0 arg1 arg2 etc'}}

Dynamic arguments are used to interface with a component.

Let’s say I’ve written a widget – a filter search field. Now, this widget is used many places in the application, but in some instances I want the input to be throttled.

So, in those cases, I include my widget like this:

{{> myWidget throttle=500}}

And inside the widget template, this keyword argument is passed on to the binding:

<template name="myWidget">
  <input {{bind 'value: value' throttle=throttle}}>
</template>

Make sense? :four_leaf_clover:


Classes

I think that’s a fair call – to be able to just write the viewmodel properties that equal classes.

So I’ll extend the classes binding now to use its args, with the optional classes keyword argument still taking precedence.

So the binding can be used like this:

<p {{bind 'classes: red large hidden'}}></p>
// viewmodel
{
  red: true,
  large: false,
  hidden: true
}

Version 0.5.7 fixes the bug with multiple bind expression, improves the classes binding (as described above)

(It also contains a tiny API change, where the args argument now contains the key as the first item.)

1 Like

Version 0.5.8 is released with a tiny API change. The section in the docs for the classes binding has been updated.

(The actual viewmodel property (getter-setter) is passed to get instead of its key, because this is what I originally meant was the most correct interface, and the key now has become available as the first item in args.)

I’m changing to a new user after this post, btw.

Hi @deb, or whatever name you have now!

Thanks for your example using dynamic arguments; I didn’t think about it, as I’ve never done it like that. I’ve always used the parent’s onRendered hook to access the child and set the values that way, which seems stupid compared to your solution. So that makes sense. Another suggestion here: what do you think about prefixing those dynamic options with an underscore or so? That way we could have code like this, which looks clean to me:

{{> myWidget throttle=500}}

<template name="myWidget">
  <!-- Edge case: -->
  <input {{bind value='email 100' enterKey=submit _throttle=throttle}}>
  <!-- But this would be normal: -->
  <input {{bind value=password enterKey=submit}}>
</template>

I totally get where you’re coming from, regarding the keyword bind syntax – it’s more Blaze native than using strings. A thing to keep in mind, though, is that we’ll never be able to skip the quotation marks around property names.

Another thing is, that there’s currently no way of passing neither positional nor keyword arguments to a helper in Jade (mquandalle:jade), without resorting to Spacebars syntax.

Least of all with attributes, I’m afraid.

Aside from all that, I think it’s wisest to keep hidden rules, such as conventions about the naming of keyword arguments, to an absolute minimum.

I have added the possibility in the next version, though, of using commas to separate multiple bind expressions inside a single string.

So instead of this:

<input {{bind 'value: value' 'disabled: disabled'}}>

… you may choose to write:

<input {{bind 'value: value, disabled: disabled'}}>

I’m currently looking into a better syntax for Jade.

Instead of this:

input($dyn='{{bind "value: value"}}')

… I would like to be able to write this:

input($bind='value: value')

To enable this syntax, I need just one out of the following two scenarios – presented here in order of their usefulness:

  1. That the mquandalle:jade package automatically convert attributes starting with $ directly to dynamic attribute helpers. So that any identifier following a dollar sign denotes a Blaze dynamic attribute helper – just like the word “bind” above.

    It only takes the four lines of code that I’ve submitted to mquandalle:jade-compiler in this pull request.

    This feature is fully backwards compatible, since attributes beginning with $ have so far resulted in an exception (except for the special $dyn attribute, which is left untouched by my pull request).

    You may be valiant enough to add some encouraging comments under my pull request, backing up the idea :+1:

  2. Or – that the mquandalle:jade-compiler package export its TemplateCompiler class. Or at least add it as a property on the main export, JadeCompiler.

    I’ve gone ahead and created an issue about it, and supportive comments will be cherished there, too :wink:

    Exporting this class would make it possible for me to release a special version for Jade – dalgard:viewmodel-jade – which would include quandalle:jade-compiler and extend it to support the new syntax in a few lines of code.

    I’ve actually implemented this solution in the develop branch of the project, by simply copying the latest version of mquandalle:jade-compiler into my root packages folder and adding the additional export statement to it.

In summary, I hope to have a solution to the Jade syntax soon – preferably the first one. Fingers crossed…

4 Likes

Sure, I didn’t think about the fact, that Blaze will always return the value, not the function, and I couldn’t find a way to get the passed property’s name …
So I guess having the comma separated syntax is a good thing, I like it!

I also found a nice way to deal with classes:

Handlebars.registerHelper 'not', (value) ->
  !value

Handlebars.registerHelper 'class', ->
  classes = _.last(arguments).hash

  checkClass = (activeClasses, className) ->
    activeClasses.push className  if !!classes[className]
    activeClasses

  _.reduce(_.keys(classes), checkClass, []).join(' ').trim()

This will, as of Meteor 1.2, allow the following:

<input class="{{class disabled=(not valid)}}">

It doesn’t work for class names with dashes, but that’s okay I guess.

Interesting – thanks for the research. The parenthesis syntax is pretty sweet, but I think we’re quickly reaching a point where expressions in Spacebars shouldn’t become any richer.

Next stop, Blaze 2 – possibly using some kind of JSX.

Hey, Krisitian. I currently use Manuel’s awesome package. You say that your version is leaner and meaner.
So what are the exact benefits of migrating to yours?

ps I am actually disappointed with awkward jade syntax in your package - have there been any improvements?

Thanks for asking. I guess it comes down to a lot of small things – like how custom bindings are defined, how parameters may be passed to bindings, the integration with Blaze, features like persistence and shared state, and the API in general.

I’m disappointed by the Jade syntax, too, though, but I haven’t been able to get a reply from @mquandalle on my pull request, nor on the issue I’ve created with the matter.

It would be nice if it had a similar example-featured manual, like viewmodel.meteor.com. I know that’s time consuming to set up though

You’re right – this package is very much for people knowing what to expect from a viewmodel pattern. What I recommend is looking through the code of the examples while seeing them live at dalgard-viewmodel.

The examples are not pretty, but they are concise :wink:

In about one month’s time, we’re locking down the API with version 1.0, under the auspices of a new venture that I’m part of. Then, we might create a tutorial, which I think is what you’re seeking.

1 Like

It looks like development on mquandalle:jade has been set on stand-by, seeing that the last change was five months ago. Maybe the package just works for people in its current form.

Nevertheless, instead of waiting around for my pull request to be merged, I’ve re-released the package on Atmosphere, including the feature I wanted.

The alternative package is called dalgard:jade and, as expected, it works exactly like the original, except that a dollar sign marks a dynamic attribute helper. The new package is backwards compatible and passes the tests of the original.

With the dollar sign syntax, elements can be bound like this:

button($bind='click: myHandler')

As far as I’m aware, Jade still lacks the ability to pass keyword arguments to helpers without resorting to Spacebars syntax. Any input on how this issue can be dealt with is very welcome.

Cheers.

P.S. As I’ve made clear elsewhere, I have not intention of taking on the maintenance of Meteor’s canonical Jade package, but will keep my package in sync with the original.

It doesn’t, there are few things missing that would be good to have. F.e. the {{#each item in items}} syntax and {{index}} in each. The same with {{#helper param}} which you mentioned.

But Jade is so much better than HTML that few missing things are still fine. And you can use spacebar syntax for some of the missing things anyways.

dalgard:viewmodel version 0.9.1 has been released together with dalgard:jade version 0.5.0, which solves some of the problems that have been discussed.

The 0.9.0 version of dalgard:viewmodel was a major refactoring of the code base, which included a number of optimizations and improved debugging through ViewModel.nexuses. At the same time, the package was moved to Meteor 1.2.0.2, mainly for native ecmascript support.

@brajt: Version 0.5.4 of dalgard:jade adds support for @index. The in syntax of each item in items has been supported for a while, I think.

1 Like

Yeah I’ve seen it on github when you added it, great news! Good work and thank you. I can finally get rid of my index mappings now. :wink:

As for each item in items it was supposed to work, there were tests for that, but somehow I fail to use it. I’ll check again, just to make sure.