Getting undefined on meteor method

Hi,

I have a small app that fetch data or weather report. It’s working server side as i can have the data oon my console.log on the server. but i get an “undefined” return on the client side as i send a call from the client.

here is my client js file :

import { Template } from ‘meteor/templating’;
import { ReactiveVar } from ‘meteor/reactive-var’;

import ‘./main.html’;

Template.hello.onCreated(function helloOnCreated() {
// counter starts at 0
this.counter = new ReactiveVar(0);
});

Template.hello.helpers({
counter() {
return Template.instance().counter.get();
},
});

Template.hello.events({

‘click .btn’: function (evt) {

var latitude = 43.6109200;
var longitude = 3.8772300;

  	Meteor.call('sendData', latitude, longitude, function(error,response){
  	            if(error){
  	              console.log('ERROR :', error);
  	            }else{
  	              console.log('Response :', response);
  	            }
  	          })
  	       }

});

and my server js file :

import { Meteor } from ‘meteor/meteor’;

Meteor.startup(() => {
// code to run on server at startup

Meteor.methods({

  'sendData': function(latitude,longitude){
  	 var weatherman = require( "weatherman.io" );
   var citiesArray = [
   {
   	name: "Montpellier",
      latitude: 43.6109200,
      longitude: 3.8772300
  },
  {
   	name: "Nîmes",
      latitude: 43.8333300,
      longitude: 4.3500000
  }];
  var options = {
      units: "si",
      lang: "fr",
      exclude: ["minutely", "alerts"],
      extend: "hourly"
  };

  var alRoker = new weatherman( "db0ee89a0f17a93af5b7556eaf28db18", options );
  var forecastOptions = {
      latitude: latitude, //43.6109200,
      longitude: longitude //3.8772300
  };
  alRoker.doForecast(forecastOptions, function (err, weatherReport) {
  if (err) {
      console.log(err);
  }
  // do something with the weatherReport 
		console.log(weatherReport.currently);
		return weatherReport.currently;
  } );
  }

})

});
Assuming, it’s a sync issue, I have already tried to use Metero.wrapAsync and Future but i don’t get it
right

can you help me on this ?

thank you

Best regards

Fabien

You are getting undefined because your method use an asynchronous function.
When you write “return weatherReport.currently” you are not returning from the method, but returnin from the callback passed to the asyncrhonous function doForecast.
Hence when the method ends, the return value from doForecast is not know at the time and so you have no way to know what value to return.
For this to work, you have to use wrapasync with your doForecast fucntion.

More explanations here : https://guide.meteor.com/using-npm-packages.html#async-callbacks

Thank you Vjau,

i changed my code to use the wrapAsync but this time it seem there’s an error in the npm packet

my changed code on my server js file :

Async = Meteor.wrapAsync(alRoker.doForecast);

  Async(forecastOptions, function (err, weatherReport) {
  if (err) {
      console.log(err);
  }
  // do something with the weatherReport 
		console.log(weatherReport.currently);
		return weatherReport.currently;
  } );

return in the server console :

Exception While invoking method ‘sendData’ TypeError: Object [object global] has no method “_forecast” at Weatherman.doForecast (c:/… ->weatherman.js)

do you think it’s related with the npm package or there’s a workaround ?

thank you

I’m not really familiar with wrapAsync but i guess that instead of writing
Meteor.wrapAsync(alRoker.doForecast)
you should write
Meteor.wrapAsync(alRoker.doForecast.bind(alRoker))

Let me know if it solved your problem.

this time i don’t get an error on the server console but i get “undefined” again on y client console

You are still passing a callback to the wrapped function.
Instead, you should only write

const res = Async(forecastOptions);

If you want to catch errors, you have to add a try/catch block.

There are two issues here.

The first is the need to wrapAsync in the server:

Meteor.methods({

  'sendData': function(latitude, longitude) {

    const weatherman = require("weatherman.io");

    const citiesArray = [
      {
        name: "Montpellier",
        latitude: 43.6109200,
        longitude: 3.8772300
      },
      {
        name: "Nîmes",
        latitude: 43.8333300,
        longitude: 4.3500000
      }];

    const options = {
      units: "si",
      lang: "fr",
      exclude: ["minutely", "alerts"],
      extend: "hourly"
    };

    const alRoker = new weatherman("db0ee89a0f17a93af5b7556eaf28db18", options);

    const forecastOptions = {
      latitude: latitude, //43.6109200,
      longitude: longitude //3.8772300
    };

    const syncDoForecast = Meteor.wrapAsync(alRoker.doForecast, alRoker);

    try {
      const weatherReport = syncDoForecast(forecastOptions);
      console.log(weatherReport.currently);
      return weatherReport.currently;

    } catch (err) {
      console.log(err);
      throw new Meteor.Error('some', 'error');
    }
  }
});

on the client, you need to set your reactiveVar in the success part of the callback:

Template.hello.events({

  'click .btn': function(evt, instance) {
    var latitude = 43.6109200;
    var longitude = 3.8772300;

    Meteor.call('sendData', latitude, longitude, function(error, response) {
      if (error) {
        console.log('ERROR :', error);
      } else {
        console.log('Response :', response);
        instance.counter.set(response);
      }
    })
  }
});

Ok, finally working by understanding the second callback :slight_smile:

i didn’t knew about the “bind” possibility

the code now is :
Meteor.methods({

'sendData': function(latitude,longitude){


	 var weatherman = require( "weatherman.io" );


	 var citiesArray = [
	 {
	 	name: "Montpellier",
	    latitude: 43.6109200,
	    longitude: 3.8772300
	},
	{
	 	name: "Nîmes",
	    latitude: 43.8333300,
	    longitude: 4.3500000
	}];


	var options = {
	    units: "si",
	    lang: "fr",
	    exclude: ["minutely", "alerts"],
	    extend: "hourly"
	};

	var alRoker = new weatherman( "db0ee89a0f17a93af5b7556eaf28db18", options );

	var forecastOptions = {
	    latitude: latitude, //43.6109200,
	    longitude: longitude //3.8772300
	};


	Async = Meteor.wrapAsync(alRoker.doForecast.bind(alRoker));

	const res = Async(forecastOptions);

	 return res.currently;
}

})

Thank you for your help

Exception While invoking method ‘sendData’ TypeError: Object [object global] has no method “_forecast” at Weatherman.doForecast (c:/… ->weatherman.js)

That may be a third issue. Have you tried import instead of require?

import weatherman from 'weatherman.io';

This form should be compatible with require syntax, although it will need to go with your other import statements at the top of the file.

I want to display my excel sheet on browser. And for same i am writing below code on server side but i am getting error like Exception while invoking method ‘filehere’ undefined

Meteor.methods({
‘filehere’ : function (messageData){
var fs = Npm.require(‘fs’);
var path = Npm.require(‘path’);
var basepath = path.resolve(’.’).split(’.meteor’)[0];
console.log(basepath);
var excel = new Excel(‘xls’);
var workbook = excel.readFile(basepath+’/server/MeteorJs.xls’);

   },

});  

can you fix this issue???

Thanks in advance