Pass a state object to be modified by each dynamic template instance

Think I found a problem without a clean solution.

I’m working on an app that involves a user adding a series of steps, each of which modifies a state object. Each type of step has its own template, and each template modifies the state in a different way. The state after the last template is displayed. The user can add steps add the end of the list, or insert new ones between existing ones. If the steps are reordered, changed, or deleted, the final state should update accordingly (ideally while only recalculating state changes after the modified step).

I haven’t yet found a clean way to set this up so that an object is passed between each template instance in an {{#each}} loop and modified before being passed to the next instance.

Does anyone have insight on how to rig up this weird hybrid of templates and state machine?

A simpler example of the general problem, and what’s already in place:

A state object has a two attributes, volume and density.
There are four types of step that alter the state:

  • AddWater
  • Input parameter: added volume of liquid
  • Effect: increases state.volume, decreases state.density
  • AddSugar
  • Input parameter: added mass of sugar
  • Effect: increases state.density
  • Boil
  • Input parameter: length of boil time
  • Effect: decreases state.volume, increases state.density
  • Drain
  • Input parameter: volume removed
  • Effect: decreases state.volume

I’ve got it set up to display different templates dynamically.

The step template:

<template name="Step">
  {{> stepTemplate}} 
</template>

The dynamic template helper:

Template.Step.helpers({
    stepTemplate: function() {
        switch (this.stepType) {
            case 'addLiquid':
                return Template.StepAddLiquid;
            case 'addSugar':
                return Template.StepAddSugar;
            case 'boil':
                return Template.StepBoil;
            case 'drain':
                return Template.StepDrain;

An example of one of the steps:

Template.StepDrain.inheritsHelpersFrom("StepBase");
Template.StepDrain.inheritsEventsFrom("StepBase");

Template.StepDrain.helpers({
    stateChange: (inputState) => {
        outputState = inputState;
        outputState.volume -= Template.instance().data.volume;
        return outputState;
    },
});

And the {{#each}} loop:

{{#each sortedSteps}}
  {{> Step }}
{{/each}}

If we put to one side the templates, then what you essentially are simulating is a spreadsheet formula. In which case, Meteor’s reactive variables will let you do this really easily.

result = f(reactiveVar1, reactiveVar2, ...)

Whenever any reactiveVar changes the result is recalculated.

Check the Tracker docs for more information, or shout up on the forums :slight_smile: