Accessing template object from package

Hello! I’m in the process of separating my app into packages. I’m closely following the structure of the Telescope meteor project. I’ve run into a problem when trying to access the Template object in JS code from a package I create.

TLDR; I can access the Template object through logging from a JS file in my package, but if I try to work with the Template object in that same file, I get a “Cannot read property X of undefined” error.

Here’s the full description of my setup and issue:

I’m running Meteor 1.2.1

app:lib - Package.onUse function:

api.use([ // meteor & shared atmosphere packages here ]);

api.export([ 'App', '_', 'Meteor', 'Template', 'Blaze' ]);

app:core - Package.onUse function:

api.use([ 'app:lib@0.1.0', 'app:start@0.1.0', // other local packages here ]);

app:start - Package.onUse function:

api.use([ 'app:lib@0.1.0', // a couple other packages ]);
api.addFiles([ 'lib/start.js' ], ['client','server']);

api.addFiles([ 'lib/client/templates/start_layout.html', // renders fine 'lib/client/templates/start_form.html' // renders fine ], ['client']);

lib/start.js

I can log the Template object and my Template instance to the console fine.
console.log(Template) // works
console.log(Template.start_form) // works

If I try to do anything with the Template object, like try to setup helpers or events on a specific template, or even just set a global helper with Template.registerHelper(), I get an error:

Template.start_form.onRendered = function() { console.log("test"); }

TypeError: Cannot read property 'start_form' of undefined at Package (lib/start.js:9:9)

Has anyone experienced this before? Or any tips on how I can continue to troubleshoot? Any help is hugely appreciated!

-Alan

Basically everything is fine, but I believe you’re missing the package responsible for blaze templates. I believe, because you didn’t paste the list. :wink:

Just add a package called “templating”, it’s core package so it doesn’t need specifying a version.

Also, don’t export Template, Meteor and Blaze. You can see that telescope-lib exports only its own thing called templates. Template exporting is done in templating package, so your export may interfere with that.

I’ve tried @brajt’s suggestions (thank you!) and have played around with the templating packages included in app:lib, but that hasn’t solved the issue. Neither has removing Blaze, Template, and Meteor from my exports function. (Though after removing the Template export the error I get is now “Template is not defined.”)

I originally had the blaze-html-templates installed. I tried explicitly adding its dependencies, and have also tried replacing it with the templating package, which you can see in my current lib package list below.

var packages = [ 'meteor-base', 'mobile-experience', 'mongo', 'templating', // 'blaze-html-templates', 'session', 'jquery', 'tracker', 'es5-shim', 'ecmascript', 'autopublish', 'insecure', 'juliancwirko:postcss', 'npm-container', 'check', 'email', 'kadira:blaze-layout', 'kadira:flow-router', 'underscore', 'mrt:jquery-easing', 'sacha:spin', 'okgrow:router-autoscroll', 'audit-argument-checks', 'browser-policy' ];

It’s a minimal working, tested version. When I remove ‘blaze-html-templates’, I see your error “Template is not defined”.

I run it on 1.2.2-faster-rebuilds.0

/packages/lib/package.js

Package.describe({
  name: 'brajt:test-lib', 
  summary: 'Test lib package.',
  version: '0.0.1'
});

Package.onUse(function (api) {
  api.versionsFrom(['METEOR@1.2']); 
  
  var packages = [
    'meteor-base',
    'blaze-html-templates'
  ];

  api.use(packages);

  api.imply(packages);
});

ln -s /var/www/test/packages/lib/brajt:test-lib brajt:test-lib

/.meteor/packages

brajt:test-lib

/test.html

<body>
 {{> test}}
</body>

<template name='test'>
  <p>Is it working?</p>
  <p>{{brajt}}</p>
</template>

/test.js

if(Meteor.isClient) {
  Template.test.helpers({
    brajt: 'working'
  });
}

Thanks @brajt. I’ve looked over your example above, and even upgraded to the 1.2.2-faster-rebuilds.0, but still no luck.

I’m wondering if there’s some reason why the Template variable wouldn’t be available to my package, since I can access it from the console like so:

I’ll keep exploring :slight_smile: I may just start from scratch like you’ve shown.

I’ve found a fix, I was including the file that was accessing the Template object on both the client and server. Changing that to only include it on the client causes the error to go away. I suppose it makes sense that the Template object would only be made available on the client… :smirk:

api.addFiles([ 'lib/start.js' ], ['client']);

instead of:

api.addFiles([ 'lib/start.js' ], ['client','server']);

:thumbsup:

Glad it’s working now. :slight_smile:

Actually, the first thing I did was to check if all your template files are only on client, but I assumed a file called lib/start.js wouldn’t be a template but some startup thing. After all you had separate files for templates start_layout.html and start_form.html and both were only on client. My fault for not reading your question to the very end.

I didn’t realize you had javascript template files called different way than your html files, because that’s such a bad practice that it didn’t even pass my mind.

Keeping multiple template definitions in one file is among things that later lead Blaze developers to have code organization problems, switch to React and claim that React is so much better because it’s better organized. When it’s actually their own fault for doing it the wrong way.

You’re totally right, I’ve since realized it was confusing and renamed it to match the template html name. I even thought for a moment Meteor might’ve been treating it as a special file because of its name. Really drives home the point that good organization practices don’t just help you, but also others understand your code. :smile:

Thanks so much for your help @brajt!

2 Likes