Component/Template custom events

Lets assume i have a form template with all business like method calling, validating, etc. I want reuse this component in different places in application. So my question is simple: how to inform parent template about state of child (my form template), e.g. after form data submitting. Till now i have found some ideas:

  1. Use Session - don’t like this way but simplest
  2. Trigger some custom event which can be caught in parent like any other events like click, etc. - how???
  3. Directly change some dict in parent (using “closest” monkey patch) - feasible but…
  4. Render in child template button: “Close form”, and catch this click event in parent - use this method for now

Any other ideas?

P.S. I don’t use routing - have SPA

Check out ViewModel. Specifically the controls section.

These are a few examples of what you can do…

Referencing a single child from the parent:

<template name="parent">
  {{> child ref='myChild'}}
</template>
Template.parent.viewmodel({
  callChild: function() {
    this.myChild.doSomething();
  }
})

Calling a parent function from the child:

<template name="parent">
  {{> child }}
</template>
Template.child.viewmodel({
  callParent: function() {
    this.parent().doSomething();
  }
})

Referencing all children from the parent:

<template name="parent">
  {{#each collection }}
    {{> child }}
  {{/each }}
</template>
Template.parent.viewmodel({
  callChildren: function() {
    this.children().forEach(function(child) {
      child.doSomething();
    });
  }
})

Wow. It look really great. Like sth that, i in my opinion, is the major lack in meteor. But… im not happy with flow direction in your example “Calling a parent function from the child”. Why not listen (in parent) for state change in child and react for that? Can it be done with viewmodel?

Sure, I’ll expand “Referencing a single child from the parent”

<body>
  {{> parentWithTotal}}
</body>

<template name="parentWithTotal">
  {{> childWithValue ref='child1' }} + {{> childWithValue ref='child2' }}
  = <label {{b "text: sum"}}></label>
</template>

<template name="childWithValue">
  <input {{b "value: number"}}>
</template>
Template.parentWithTotal.viewmodel({
  sum: function() {
    return parseInt(this.child1.number()) + parseInt(this.child2.number())
  },
  autorun: function() {
    console.log(this.child1.number() + " + " + this.child2.number() + " = " + this.sum());
  }
});

Template.childWithValue.viewmodel({
  number: 0
});

Output:

I included an autorun that “listens” for changes in the children but I rarely have to do something like that because all values and functions are reactive in ViewModel.