ReferenceError: wData is not defined


#1

Hi all, I’m new here :smile:
I need help with my first project :stuck_out_tongue:

I have this code in the Server folder…

if (Meteor.isServer){
  Meteor.methods({
    'getData' : function() {
      return Meteor.http.get("http://api.openweathermap.org/data/2.5/weather?q=boston");
    }
  });
}

And this code in the Client folder…

  Template.storiesList.helpers({
    'wData' : function() {
      Meteor.call('getData', function(err, res) {
        Session.set('wData', JSON.parse(res.content).weather[0].description);
        console.log(wData);
      });
      return Session.get('wData');
    }
  });

Along with this Template…

<template name="storiesList">
<div class="storyList">

<p>{{wData}}</p>

  </div>
</template>

and IT WORKS :smiley:
But the browser console throws me this error, with a big 2 near it…
Exception in delivering result of invoking ‘getData’: ReferenceError: wData is not defined

I tried messing around with the parts indicated there but, I can’t seem to be able to figure out what the problem is :frowning:

Thanks in advance for any help!


#2
console.log(wData);

That isn’t defined anywhere, you should log something like res.content.

Also - Meteor Methods are usually good to go in a shared folder (client/server) so that clients can do latency compensation. They will simulate the method immediately and wait for a server response. Probably wont do anything with your method here, but normally it would update a database or whatever.

Edit #2 - When you have files in a server directory, you don’t need the conditional wrapper if (Meteor.isServer) because it is only run on the server anyway.


#3

YES!
It worked, thanks a lot! :smiley:
ANd I also removed the useless if statement, I forgot to clear that up after I split the code in the appropriate folders >_<


#4

No worries, there are better ways to do what you’ve got in your example.

You should look into using a ReactiveVar attached to the template where this is being displayed.
You will need to add reactive var meteor add reactivevar.

Then you can add this function to your client somewhere:

Template.storiesList.onCreated(function() {
    var self = this;
    self.weatherData = new ReactiveVar();
    Meteor.call('getData', function(err, res) {
      self.weatherData.set(JSON.parse(res.content).weather[0].description);
    }
  });
});

Then your helper can look like this:

Template.storiesList.helpers({
  'wData' : function() {
      return Template.instance().weatherData.get();
  }
});

The reason this way is preferred is you are not using the global Session variable. These are bad because if you’re using them everywhere then you can easily lose track of which means what. It is a little strange the way you’re calling the method in the helper, it is confusing, it almost should cause an infinite loop.

Each time the helper runs, it is setting the Session, which is reactive, and it should then call the method again.


#5

I’m very new to all of this (Javascript, Meteor and programming in general).
So thanks a lot :smile:

Could you explain to be the bit where you do “var self = this;” ?


#6

Sorry I had an error and have updated that section.

I have run into issues with the scope of this before and find it easier to define a variable as this to preserve the scope.
To be honest with you, I have just been doing that for a while now and am not certain if I even need to do it.
I’m not an expert with JS and this is something that confuses lots of people.


#7

You definitely need to preserve the scope of this when wanting to use it within a callback as used here.

For the example shown, the onCreated function has its own local set of variables and methods (its scope). These are attached to the this object.

However, every function has a this object - its own scope. So, when we need to access an outer scope’s this, we first make a copy of the reference (often we use self). Because of the way JavaScript works - outer scoped variables are available inside child functions - self (the parent’s this) is available within the callback function of the Meteor.call. We need it there, because we want to access weatherData, which is attached to the parent function.

Strictly, it’s unnecessary to use self.weatherData = new ReactiveVar(); - it could equally be this.weatherData = new ReactiveVar();, or even var weatherData = new ReactiveVar();

To add to the confusion, ES2015 is going to shake this up a bit ('nuff said :wink:).


#8

:smile: brilliant thanks for jumping in!
I knew I was at least half way there with what I said.