Meteor, call function in child template from parent template
Asked Answered
I

4

9

If I have a parent template Container with a child template Content avec only a button :

<head>
    <title>test</title>
</head>

<body>
    {{> Container}}
</body>

<template name="Container">
    {{# Content callback = callBack }}
        <button>ok</button>
    {{/Content}}
</template>

<template name="Content">
    {{> UI.contentBlock}}
</template>

If can pass a function to the callback. Like that :

Template.Container.helpers( {
    callBack: function () {
        return function () {
            console.log( 'this is my callback' );
        }
    }
} );

So in my content template, I can call a function from my parent template. Like this for instance :

Template.Content.events( {
    'click button': function ( e, tmpl ) {
        tmpl.data.callback();
    }
} );

But sometimes, I need to make it happen the other way. The parent calling a function in his child. What's your way of doing it ?


EDIT :

I saved it in a meteorpad to show it in action and to make it easy to fork : http://meteorpad.com/pad/48NvCFExxW5roB34N/test-pass-callback-to-parent

Interdisciplinary answered 1/12, 2014 at 13:25 Comment(0)
A
16

Here's a pattern you could use. Define a class Child and a template child; the idea is that inside the child template, the data context is a Child instance. For example, I'll create a component which has a number that can be incremented by pressing a button.

<template name="child">
  <button class="increment">{{number.get}}</button>
</template>
function Child() {
  this.number = new ReactiveVar(0);
}

Template.child.events({
  "click .increment": function () {
    this.number.set(this.number.get() + 1);
  }
});

In the parent's created callback, create a Child instance and store it on the template instance. Then in the parent template, call out to child, passing in the Child as a data context:

Template.parent.created = function () {
  this.childInstance = new Child();
}

Template.parent.helpers({
  childInstance: function () {
    return Template.instance().childInstance;
  }
});
<template name="parent">
  {{> child childInstance}}
</template>

Now you can define methods on the Child prototype and call them from the parent template, for example:

Child.prototype.getNumberTimesTwo = function () {
  return this.number.get() * 2;
}
<template name="parent">
  {{> child childInstance}}
  That number multiplied by two is: {{childInstance.getNumberTimesTwo}}
</template>
Arteriotomy answered 2/12, 2014 at 9:19 Comment(1)
I've used an event emitter for communications between templates before, you pass the event emitter to the child template just as above, it works quite well. The child template can also emit events to be received by the parent template.Afghani
T
2

Based on my experience with Meteor, it seems like it favors more of an event driven UI design. This means that you would not directly call the parent or child methods directly, but you would fire a custom event or set a Session variable. So you could do something like:

Template.Container.helpers( {
    callBack: function () {
        Session.get('button.lastClickTime');
        console.log( 'this is my callback' );
    }
} );
Template.Content.events( {
    'click button': function ( e, tmpl ) {
        Session.set('buttom.lastClickTime', new Date());
    }
} );

The Session object is reactive so the callback method will be called anytime that 'button.lastClickTime' Session value is set.

Then you could just reverse the set/get calls to notify the child from the parent.

Tameshatamez answered 1/12, 2014 at 17:4 Comment(0)
H
1

You can register an event handler on the parent template that triggers on events in the child template by using a Selector that matches elements in the child template, like this:

Template.Container.events( {   // 'Container' is the parent template
    'click button': function ( e, tmpl ) {    // Selector for an element in the child-template*
        // You will now have access to the parent's context instead of the child's here.
    }
} );

*) Assuming there are no other buttons in the parent template. If so, make a unique name to the button so you can uniquely select it from the parent.

Husbandry answered 1/12, 2014 at 17:11 Comment(1)
That could work in another case. But in mine, the Content is a component and will appear multiple times in the parent template. And the goal is to access the child context from the parent, not to access the parent from the child.Interdisciplinary
L
0

You can also create template functions in the child and then set those on the parent when the child gets created. This requires use of the meteor-template-extension package. Though if you dig into that package you could just pull out the code that does the parent() function.

Template.child.onCreated(function() {
   let instance = this;
   instance.someFunction = function() {...};
   instance.parent(1, false).someFunction = instance.someFunction;
});

Then this can be called by the parent in an event handler (or anywhere) for example.

Licence answered 20/11, 2019 at 2:24 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.