2

I've come across this situation several times now and I realise I'm not really confident about the 'meteor/right' way to handle it.

Suppose I have a form with several parts - each represented by a template - and within each part there are more templates representing eg. datepickers etc.

<template name='myForm'>
    {{>partOne}}
    {{>partTwo}}
    <button class='submit'>Submit</button>
</template>

<template name='partOne'>
    {{>widget}}
    {{>widget}}
</template>

<template name='widget'>
    <input class='datepicker' />
</template>

I want to keep track of my form as the user fills it out - on the level of the 'myForm' template - but all the events are happening at the level of 'widget'.

One solution I keep seeing (e.g. in this SO answer) is to just put everything in the global Session variable. Like so

Template.widget.events({
    'click .select' : function(event, template){
        var name = template.data.name;
        Session.set(name, $(event.currentTarget).val());
    }
});

And then in myForm I should do something like this

Template.myForm.rendered = function(){
    Tracker.autorun(function(){
        var name = Session.get('name');
        // do something
    });
}

But as my forms are getting more complicated, I find this is really turning into a mess on the myForm template level, all while filling up my Session variable with data that isn't really application-global.

I'd be really grateful for any ideas on how others deal with this ! Keeping templates and widgets modular while still being able to follow and react to their triggered events from parent templates...

Community
  • 1
  • 1
Petrov
  • 4,200
  • 6
  • 40
  • 61

2 Answers2

3

You're not alone in feeling like something just isn't right. This is one of the reasons there's a lot of talk about a Blaze 2. Here's what I do:

Create an app global namespace (e.g. G = {}). I usually use the first letter of the app name & do this in lib/config/_namespace.js

Put your collections in G.Collections or G.C,

Put your shared functions in G.Fx, etc...

Put your template vars in G.T.

Then, save that variable to G.T.varName. In doing so, you can use it in rendered as well as events and helpers. As a perk, it's super easy to find all your "globals" because they're all in the G object. Additionally, you can now 'use strict' again.

Then, to keep it clean:

Template.parentTemplate.destroyed = function() {
  G.T = {};
};

So if you need reactivity, just make a ReactiveDict:

Template.parentTemplate.created = function() {
  G.T.RD = new ReactiveDict();
};
Matt K
  • 4,813
  • 4
  • 22
  • 35
  • This wasn't the approach i used to solve this particular problem, but thanks for a really useful answer all the same. There is almost no info about namespacing in the meteor literature and i've followed some of your advice – Petrov Apr 07 '15 at 22:24
1

You can use a file-level ReactiveVar or ReactiveDict, instead of the Session object.

pfkurtz
  • 494
  • 3
  • 7
  • that would work if all the widgets were in the same file... but those in other packages wouldn't have access to it – Petrov Mar 16 '15 at 22:53
  • I use a global variable `G = this` on the client and server to access the global namespace, but this wouldn't get you past having several different Session variables, that don't persist. There's not a good way in Meteor that I know, yet, to share data without making it global. – pfkurtz Mar 16 '15 at 23:08
  • I haven't tried this, but it might be possible to store a ReactiveVar on the parent template's dataset, using `Template.parentData`. – pfkurtz Mar 16 '15 at 23:11