ViewModel 2 - A new level of simplicity

All properties used by the template person are inherited from the context in people#each so there’s no need to define the person view model explicitly.

<template name="people">
  ...
    {{#each people }}
      {{> person }}
    {{/each }}
  ...
</template>

<template name="person">
  <div class="inline item">
    <a {{b "click: parent.remove(_id)"}}><i class="remove icon"></i></a>
    <span class="content" {{b "text: name"}}></span>
  </div>
</template>

See inheritance

2 Likes

I’ve just got the hang of ref property. It actually is very nifty)
Delivers me from global jquery variables.
kudos for that)

1 Like

Docs say:

It would be really nice, in case there was only one child viewmodel on on that template - .children(string) would return not an array but the viewmodel.
Instead of this.children('tpl')[0] I’d like to use simply this.children('tpl').

That sounds like trouble. What about (not if but when) the template is suddenly changed. Instant crash! How about something like:
this.children('tpl').first ?

After working with meteor for a few month I decided to try viewmodel. It’s fantastic. I’m amazed it’s just one developer. Great work. I’d like it to be an official package. Thanks for making my life easier.

3 Likes

@avalanche1 & @sscs

If you have a loop in your template like so:

<body>
  {{#each comments}}
    {{> comment }}
  {{/each}}
</body>

Then there is no doubt in my mind that the right answer for .children() is to return an array regardless of the number of elements. I don’t like the business of a function returning different types depending on what day of the month we’re in (an array for 2+ elements, an object for 1, undefined for 0?)

If your references to child templates are not in a loop, e.g.:

<template name="person">
  {{> address}}
</template>

<template name="address">
  <input {{b "value: line1"}}>
  <input {{b "value: line2"}}>
</template>

There is no better way to access address than with a direct reference to the child view model:

<template name="person">
  {{> address ref='house'}}
  <button {{b "click: logAddress"}}>Log Address</button>
</template>
Template.person.viewmodel({
  logAddress: function() {
    console.log( this.house.line1() + " - " + this.house.line2() );
  }
});

If someone has a cleaner way to handle this situation I’d love to hear it.

@sirganya

Thank you for the kind words d(^_^)b

2 Likes

Very neat example with ‘ref’.
I’ve looked it up once more in the docs and an example is there, but it’s more difficult to understand and not as obvious as this.house.line1(). Would like to see this example in the docs for ‘ref’ instead.

Btw, this topic is looking to contain a lot of useful knowledge on Viewmodel - would be nice to reference it in the docs :smiley:

2 Likes

Great examples! Thanks. I will use viewmodel 2 in my current project.

I really like what I’m seeing with ViewModel2, but I just can’t bring myself to take on something with a dependency on Blaze due to the new direction Meteor is being taken in.

It will be harder for any project like this, the ones that live outside of the Meteor recommendation. Right now, the mindshare is going to swing to React, and along with it the tools, the packages, the help etc.

I didn’t read that in the latest statement of MDG’s CEO. Blaze will be still the Meteor recommended way, but this can change in the future. At the moment, there are cases where you are faster with Blaze/ViewModel and some where React may be the better choice. Learning both shouldn’t be a problem for a developer - and if Blaze will be deprecated in 2 or 3 years, that shouldn’t be a problem. Look at the Angular guys who have to deal with breaking changes in Angular 2.

1 Like

I wish you were right, but I don’t think you are. Here’s a link to the thread where I give my take on this.

I have tons on Blaze code in production, and would love to use something like ViewModel, I just can’t after the recent MDG announcements. I guess if I get the bandwidth I’ll slowly start migrating to React sometime after 1.3 drops. :pouting_cat:

And it’s not just React, but the entire Meteor stack will morph into a stack that compliments React – basically a modified Facebook stack of sorts.

As a small startup, with a relatively large application (well over 100 Blaze screens and counting), I have to ask myself, does it make sense to invest more in Blaze and take on something like ViewModel or should I invest that time (money) into the migration to React?

Hopefully packages like ViewModel will come along that will make React easier like they have with Blaze.

I hear you.

TLDR: I’ll continue to work with Blaze/ViewModel for all applications that aren’t big enough to warrant hacking my way to get code splitting and SSR. Quite a lot of projects fall under this category (YAGNI applies here).

I usually create web apps, not websites, so the only thing I would love for MDG to come out and say is that Blaze will get lazy loading so it can be used on really big projects. Meteor has too many clients on Blaze so they’re not dropping Blaze (as in break it) any time soon.

Consider the following:

  • There isn’t anything out there that takes care of so many problems for me than Meteor (moving data between client and server, database reactivity, authentication, authorization, configuration, etc.)

  • There isn’t anything out there that allows me to write cleaner and simpler code than ViewModel (the whole component communication and state problems just disappear).

So if a Meteor/Blaze/ViewModel solution works beautifully today, why would I make my life harder just to get to the same point tomorrow? Why would I rewrite an app that, if left alone, will continue working tomorrow as well as it does today?

That said, if MDG ever comes out with a solution for React that doesn’t require hacks to get SSR, lazy loading, hot reload, etc. (afaik, the current react package doesn’t offer any of that) I will make a ViewModel that sits on top of it (the same way it now sits on top of Blaze). Here’s an example of what it could look like:

pacman.vmc

<PacMan>
  <div>
    <svg b="attr: { width: width, height: height }" style="border: 1px solid black;">
      <path b="attr: { d: path }" fill="yellow" stroke="black" stroke-width="2" />
    </svg>
    <PacManOption ref="largeArc" title="Large Arc?" name="largeArc" value="0" />
    <PacManOption ref="closePath" title="Close Path?" name="closePath" value="0" />
    <PacManOption ref="sweep" title="Sweep?" name="sweep" value="0" />
    <input type="range" b="value: radius" />
  </div>
</PacMan>

<script>
  PacMan = {
    radius: 0,
    path: function() {
      return "M 100,100 L220,60  A "
        + this.radius() + "," + this.radius()
        + " 1 " + this.largeArc.value() + "," + this.sweep.value()
        + " 220,140" + (this.closePath.value() ? "Z" : "");
    }
  }
</script>

pacmanOption.vmc

<PacManOption>
  <div>
    <span b="text: title" />
    <input type="radio" value="1" b="name: name, group: value" /> 1
    <input type="radio" value="0" b="name: name, group: value" /> 0
  </div>
</PacManOption>
4 Likes

I don’t think MDG will do anything of the sort. This is post summarizes how I think it’s going to go down with Blaze.

Right, again, it will just sit as is, as it has for a while now, until React comes up to parity both in integration and package coverage.

This will also be true once the transition of Meteor to the Facebook stack has taken place. I’m sure there will be custom solutions to make the Facebook stack easier than it is without Meteor.

I’m sure this is true to some degree (I can’t speak to it because of course I haven’t actually used it), but this is beside the point. Again, I would love to use ViewModel (it looks wonderful), and am not looking forward to using React – but if I want to say current with Meteor and the way the ecosystem is going, I need to start making the switch at some point after 1.3. I think ViewModel over React would take off.

Simply, because the community support, the examples, the documentation, the packages, the mindshare of Meteor is going the way of React and the complimentary tech around the Facebook stack. If you want to live in this world you must stay current.

The way I see it, you must choose to:

  • say current and in my case migrate to React and Redux (or whatever data transmission layer is going to prevail),

  • stay where you’re at and take on package management and all this entails as they stagnate – for example bug fixes, if you want features you’ll need to do this yourself or find like minded side communities, help will subside as mindshare moves on, etc. There’s too many risks for a small startup like mine to fall too far behind the front.

  • switch to alternative frameworks, of which there are relatively few. In my case, I’ve invested too much in Meteor as I have a large production application.

This would be excellent, I can only hope.

I agree with your sentiment but I disagree with your conclusions =)

I just don’t see the value in chasing the latest trends (making my life harder in the process, working with something I don’t like) when the worst that can happen is for my apps to work tomorrow the same way they do today. I am perfectly comfortable with that.

3 Likes

+1 insightful

This has been my biggest reluctance of investigating ViewModel further: both ‘View’ and ‘Model’ are overloaded terms, with many different interpretations. It’s just too easy to confuse it with MVC terminology. The technology looks perfectly fine; but the API adds confusion.

The value for me at least is getting code splitting (right now my client even the templates they don’t always use), UI/Server performance enhancements, SSR, tentatively more package coverage, and on and on.

I wouldn’t call waiting several releases chasing as you say, and I when I do start the React upgrade it will go slowly. I’ll wait for at least 1.3, maybe even sometime after that – I want things to settle down more before I start to migrate.

The worse for me looking out on the horizon is broken/abandoned packages, waning community help/support, and unaddressed bugs.

I love working with Blaze, but its future is uncertain and I would hesitate advising others to invest in it unless/until MDG turns it into true community driven OSS.

1 Like

Please, not another blaze v react discussion…
Let’s keep this topic a Viewmodel Q&A. I like it much better that way.

Q re ‘change’ binding:
docs say ‘The change binding executes a function when the value of the bound property changes.’ This means I have to explicitly add a ‘value’ binding - otherwise change event fires only on blur.
In my case I don’t need to bind that particular input field. I only need to catch the change event. In that case I use standard input event.
So what’s the reasoning behind having this ‘change’ binding?

You’re right that if you don’t need the value of the input (just need to know when it changes) then you’re better off using the element’s events. In the case of an input box you probably want to do:

<input type="text" {{b "input: doSomething"}}>

That said, I’ve never had an input box on a page which I didn’t use the value.

The change binding exists because you don’t always have an element’s event. It functions kinda like an autorun for a single value associated with an element. For example if you wanted something to happen when the visibility of an element changes you could use an autorun, or you could just use the change binding:

<template name="example">
  <div {{b "if: displayContent, change: do_Something_When_displayContent_Changes"}}>
    content
  </div>
</template>
1 Like

Children demo references parent.remove(_id) to access parent’s properties from mark-up. But doesn’t mention the same functionality for children.
Is there a way I could access a specific child’s property from mark-up?
Like div($b= "text: children('childVM').someProperty()")?
Currently I’m forced to create a special property on the parent which reads someProperty of childVM.