2

I'm trying to set up an MDC dialog warning. Instead of copy-pasting it into every view that requires it, I'm wrapping the dialog in its own template. The template seems to work, the dialog opens up and functions as normal, however, I can't set a helper function for it that works. I tried using the helper function of the parent template, and even creating the new template its own js file. Neither of these solutions grab the data correctly.

<template name="transactionAlert">
...
<div class="mdc-dialog__content" ><p>Are you sure you wish to continue with this transaction? It could cost up to: <b class="warning-value">${{maxCost}} USD</b></p>
...
</template>
<template name="transactionCreate">
...
    {{>transactionAlert}}
</template>
Template.transactionAlert.onCreated(function transactionAlertOnCreated() {
    console.log('test')
})

Template.transactionAlert.helpers({
    maxCost(){
        console.log('test 2')
        const instance = Template.instance()
        return instance.maxTxCost.get().toString().slice(0,5);
    }
})

1 Answers1

0

I tried using the helper function of the parent template

Such problems are often caused by design issues, rather than missing or wrong implementation. If we consider the your transactionAlert to be stateless (it does not contain any relevant view logic or internal state management) then it should also neither access properties nor helpers that are out of it's scope.

Otherwise you will create such a tight coupling that it will throw back in your face in two years or so (when the refactoring session is calling).

In contrast the responsibilities of the parent Template are to

  • manage state of the data (subscriptions, data post-processing etc.)
  • check the conditions, whether the transactionAlert should appear or disappear
  • pass the proper parameters to the transactionAlert Template

As a consequence you may design your transaction alert as a parameterized template:

<template name="transactionAlert">
...
<div class="mdc-dialog__content" ><p>Are you sure you wish to continue with this transaction? It could cost up to: <b class="warning-value">${{maxCost}} USD</b></p>
...
</template> 

As you can see it looks exactly the same. The difference is, that you remove the Template.transactionAlert.helpers and cause the Template to look for maxCost being passed to the template.

Now in your parent Template you will pass the data to the transactionalert, once the condition for alerting applies:

<template name="transactionCreate">
  {{#if showAlert}}
    {{>transactionAlert maxCost=getMaxCost}}
  {{/if}}
</template>

where the helper is now:

Template.transactionCreate.helpers({
    showAlert () {
      return Template.instance().showAlert.get()
    },
    getMaxCost(){
      const instance = Template.instance()
      return instance.maxTxCost.get().toString().slice(0,5);
    }
})

Because you need reactivity to show/hide the alert you will make use of the Template's internal Tracker:

Template.transactionCreate.onCreated(function () {
  const instance = this
  instance.showAlert = new ReactiveVar(false)
  instance.autorun(() => {
    const maxCost = instance.maxTxCost.get()
    if (/* max cost exceeds limit */) {
      instance.showAlert.set(true)
    } else {
      instance.showAlert.set(false)
    } 
  })
})

Edit: Additional information on reactivity

Reactivity is a main concept of Meteor's client ecosystem. It bases on the Tracker package, which is linked to any Template instance. The guide to the reactive data stores explains the concept a bit further: https://guide.meteor.com/data-loading.html#stores

Jankapunkt
  • 8,128
  • 4
  • 30
  • 59