How can I Import a reactive source

Basically I have a configuration document in the Config collection. I want to retrieve it once, then import that document into any other files I might need it.

So what I’m doing now is
file: /client/imports/config.js contains:
export let config = Config.findOne({
‘OrgInfo.web.domain_name’: Meteor.settings.public.org_domain
});

then in a template file I’m doing
import {config} from ‘/client/imports/config.js’;

I have several template helpers that use the new ‘config’ variable, but these helpers aren’t being updated reactively.

What am I doing wrong?

For reactive updates to work, you have to call a reactive function inside of another reactive function. We know e.g. that this works:

Template.example.helpers({
  config() {
    return Config.findOne(...);
  }
});

And we know that this wouldn’t be reactive:

// Stores the value outside of a non-reactive function
var config = Config.findOne(...);

Template.example.helpers({
  config() {
    return config;
  }
});

If you understand why the 2nd snippet doesn’t work, it should be clearer why the approach you’re taking with imports isn’t working. You could fix this by exporting a function and using that function, e.g.:

// client/imports/config.js
export let reactiveConfig = function() { return Config.findOne(...) };

// somewhere else
Template.example.helpers({
  config() {
    return reactiveConfig();
  }
});
1 Like

Thanks for that.

Since I’d have to import that each time I decided to just use a global function and skip the import. (I know, I know, shame on me. )

I noticed you have a package called config, ( https://atmospherejs.com/gadicohen/config). Do you think it would do what I’m trying to accomplish here?

But weren’t you already doing that? :slight_smile:

// config.js
export let config = Config.findOne({
'OrgInfo.web.domain_name': Meteor.settings.public.org_domain
});

// template
import {config} from '/client/imports/config.js';
doSomethingWith(config);

became:

// config.js
export let config = function() {
  Config.findOne({
    'OrgInfo.web.domain_name': Meteor.settings.public.org_domain
  })
};

// template
import {config} from '/client/imports/config.js';
doSomethingWith(config());  // now called as a function

As for my config package, wow, I haven’t thought about it for a long time :slight_smile: Yeah, I believe the idea is similar, but it doesn’t support multi-tenancy. So you can only get a config variable by name, not by name and a custom variable from Meteor.settings. And you’d still have to handle the reactivity. If you look at the config source, it’s (purposefully) very simplistic.

I wasn’t already using a global variable if that is what you mean. I was using the export and import. Since I’m needing this config document all over the place it makes more sense to me to just make it a global then to write that import line on practically every template I use.

My main problem was coming from not waiting for the config subscription to load. For some reason my brain didn’t make the switch from not needing to wait (with the Meteor.settings) to needing to wait for it since it is coming from the collection.

Thanks

1 Like

Try this:

import {Config} from "/imports/collections/config";

import {Meteor} from "meteor/meteor";
import {ReactiveVar} from "meteor/reactive-var";

export const config = new ReactiveVar(false);

export const observer = Config.find({
  'OrgInfo.web.domain_name': Meteor.settings.public.org_domain
}, { limit: 1 }).observe({
  added: doc => config.set(doc),
  changed: doc => config.set(doc),
  removed: () => config.set(false)
});

export default config;
1 Like

Interesting. Thanks. I’ll give this a try.