0

I am struggling with what I know is a very basic question related to variable declaration. I've read everything I can find on variables but I don't know if my problem is related to 1) how I am declaring variables or 2) how I am setting the scope of the variables.

To start, my understanding of variables in Meteor is that if I use var, then I am setting file-scope, which would make that variable available to every helper for that particular template. If I do not use var, it will be global and therefore available to the helpers in every template. Is that correct?

The following block of code works fine, returning the correct value in the client:

Template.CompanyFinancials.helpers({
    priceEarningsFy1: function () {
        var compTicker = this.ticker
        var price = Companies.findOne({ticker: compTicker}).capTable.lastClose;
        var epsFy1 = Companies.findOne({ticker: compTicker}).fy1.eps;
        return (price / epsFy1).toFixed(1)
});

I have dozens of similar calculations throughout this app and many which rely on more variables than this example, so I have been trying to factor out the variables and reuse them in the template, like so:

var compTicker = function() {
    return this.ticker;
};
console.log(compTicker);
var price = function(compTicker) {
    Companies.findOne({ticker: compTicker}).capTable.lastClose;
};
console.log(price);
var epsFy1 = function(compTicker) {
    Companies.findOne({ticker: compTicker}).fy1.eps;
};
console.log(epsFy1);

Template.CompanyFinancials.helpers({
    priceEarningsFy1: function (price, epsFy1) {
         return (price / epsFy1).toFixed(1)
    }
});

With this code, console.log() actually returns the text within each function (e.g., return this.ticker) for each variable, not the value. If I declare the variables without functions, like I’ve done within the helper, it returns undefined for compTicker.

I tried to follow this answer which explains reusable code, but not clear if same use case applies. My variables point to specific fields in the database, not necessarily calculations.

Can anyone help me repair my syntax? I'm writing multiples more code than I need to with my current understanding. Thank you.

EDIT I also tried declaring the variables the same way they are declared in the helper, but these return undefined.

var compTicker = this.ticker;
console.log(compTicker);
var price = CompaniesFeed.findOne({ticker: this.ticker}).capTable.lastClose;
console.log(price);
var epsFy1 = CompaniesFeed.findOne({ticker: this.ticker}).fy1.eps;
console.log(epsFy1);

RESOLUTION: Using global helpers and returning multiple values, then using dot notation to access in the template HTML:

Template.registerHelper('priceEarnings',function(){
    var ticker = this.ticker;
    var company = CompaniesFeed.findOne({ticker: ticker});
    return {
        peFy1: (company.capTable.lastClose / company.financial.fy1.eps).toFixed(1),
        peFy2: (company.capTable.lastClose / company.financial.fy2.eps).toFixed(1)
    };
});

<td>{{priceEarnings.peFy1}}x</td>
Community
  • 1
  • 1
Bren
  • 273
  • 1
  • 18
  • You do not ever call your functions and `price` and `epsFy1` don't return anything, making them effectively useless. – Kyll Oct 09 '15 at 15:27
  • What if I declare without functions, like in the edit above? This is how I declare the variables within helpers, can it just be factored out and reused? – Bren Oct 09 '15 at 15:43

1 Answers1

1

You might be looking for global helpers. These are helpers which can be reused across all templates.

For your priceEarningsFy1 function for example:

Template.registerHelper('priceEarningsFy1',ticker => {
  const company = Companies.findOne({ticker: ticker});
  return ( company.capTable.lastClose / company.fy1.eps ).toFixed(1);
});

In this case I've specified that ticker is to be provided as an argument. From a blaze template you would use {{priceEarningsFy1 this.ticker}} for example. To refer to this function from js code use UI._globalHelpers.priceEarningsFy1(ticker)

Note that any local functions you define inside a given file are available to any other functions inside the same file. My pattern is to put all my global helpers in one file sorted by name and then at the bottom add various utility functions for use by the global helpers. This keeps things relatively dehydrated.

Michel Floyd
  • 18,793
  • 4
  • 24
  • 39
  • I've used global helpers for other purposes, I'll give this one a shot. But wouldn't this clutter the HTML code? I have some helpers that rely on 5 or 6 variables. I'm also not looking, for now, to reuse across templates. I'd be happy if all the helpers from just one template were able to rely on the same variable. – Bren Oct 09 '15 at 15:47
  • Also, in your example, `company` is still declared from the global helper. When I write the `priceEarningsFy2` global helper, I'll then need to declare it again, which unfortunately gets me back to where I started. – Bren Oct 09 '15 at 15:53
  • It won't clutter the HTML code because it's js. It won't clutter the js either because you need to create these functions *somewhere*. `company` is a temporary variable whose scope is restricted to that function. You can't define `compticker` outside the helper scope because `this` will point to the `window` and not to the data context of the helper. You can also return multiple FY P/E values in one object and use them in your templates. – Michel Floyd Oct 09 '15 at 16:24
  • Thanks. I'll spend some time on this. By "clutter the HTML", I meant where you use `{{priceEarningsFy1 this.ticker}}`. I have other instances where I have needed to add more than one global helper. But I'm just speculating until I try to implement this. Your point on not being able to define `compTicker` outside the helper scope is appreciated, I've been looking for confirmation on that. – Bren Oct 09 '15 at 16:35
  • Also. to return multiple FY P/E values, I assume you mean I could define a global helper just named `priceEarnings` and then run an `if` statement within to change the period? – Bren Oct 09 '15 at 16:36
  • You could pass FY as a second argument or you could return multiple years of P/E as an object, ex: `{ pe1: value1, pe2: value2 }` – Michel Floyd Oct 09 '15 at 20:06
  • Michel, your last point is great, given I need to display results for several periods at the same time. If I return an object with several values, ex: `{pe1: value1, pe2: value2}`), should I be able to apply dot notation to the global helper in the template HTML? I'm trying `priceEarnings.pe1`. It's showing `[object object]`. – Bren Oct 09 '15 at 21:02
  • Yes, you can do dot notation in spacebars, I use this all the time. If `{{priceEarnings.pe1}}` is returning `[object object]` that means that `pe1` is itself an object and you've introduced an extra level in your hierarchy. – Michel Floyd Oct 09 '15 at 21:58