Trigger event when page loads


#1

Hi,

I created a small app that fetch data from a weather API.

The process is started when i clic on a button but i can’t figure oit how to do it simply when the page loads.

my main.html file code is :

<head>
  <title>wthr</title>
</head>

<body>
  <h1>Weather app</h1>

  {{> hello}}
  
</body>

<template name="hello">
  <button class="btn">Click Me</button>
  <p>La prévision météo est {{counter.currently.icon}} avec un un indice ozone de {{counter.currently.ozone}}</p>
</template>

My main.js on the client side is :

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,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);
			
			}
		})
	}	


});

and my main.js code on the client side is :

import { Meteor } from 'meteor/meteor';

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

  Meteor.methods({

  	'sendData': function(){

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

		 var citiesArray = [
		 {
		 	//name: "Montpellier",
		    latitude: 43.6109200,
		    longitude: 3.8772300
		},
		{
		 	//name: "Nîmes",
		    latitude: 43.8333300,
		    longitude: 4.3500000
		}];
 
 
console.log(citiesArray[1].latitude);

		var options = {
		    units: "si",
		    lang: "fr",
		    exclude: ["minutely", "alerts"],
		    extend: "hourly"
		};
 
		var alRoker = new weatherman( "db0ee89a0f17a93af5b7556eaf28db18", options );

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


		Async = Meteor.wrapAsync(alRoker.doForecast, alRoker);
 
		const weatherReport = Async(forecastOptions);
      	//console.log(weatherReport);
      	return weatherReport;
	
  	}
  })


});

how can i start the whole process directly when the html page is loaded instaed of clicking a button ?

thanks


#2

Try using the onRendered method, probably attached to your hello template.


#3

ok so i tried :

Template.hello.rendered = 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);
			//return response;
			instance.counter.set(response);
			//instance.counter.set(instance.counter.get() + 1);
			}
		})
      //alert('load');
    
}

but the Meteor.call doesn’t seem to be launched


#4

Hm, the syntax should be:

Template.hello.onRendered(function () {
  // Your code
});

#5

as i did a simple test with alert('load); it was working

anyway i changed the “onRendered” but the behaviour is the same


#6

So you see the console logs, or no?


#7

yes, it says :

Exception in delivering result of invoking 'sendData': TypeError: Cannot read property 'counter' of undefined

my helper on the template Hello is :

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

});

it seemthat the isnance value is not received, no ?


#8

Right, so if you check out http://docs.meteor.com/api/templates.html#Template-onRendered, you’ll see that you don’t use instance in the onRendered callback.

Instead:

Template.hello.onRendered(function () {
  var latitude = 43.6109200;
  var longitude = 3.8772300;
  var self = this;
  Meteor.call('sendData', latitude, longitude, function (error, response) {
    if (error) {
      console.log('ERROR :', error);
    } else {
      console.log('Response :', response);
      //return response;
      self.counter.set(response);
      //instance.counter.set(instance.counter.get() + 1);
    }
  });
});

#9

If you will accept some minor refactoring, this is what I’ve got. Your client template methods:

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

import './main.html';

Template.hello.onCreated(function helloOnCreated() {
  this.counter = new ReactiveVar();

  // Set up a template function to change the city
  this.changeLocation = (city) => {
    Meteor.call('sendData', city, (error, response) => {
      if (error) {
        console.log('ERROR :', error);
      } else {
        console.log('Response :', response);
        this.counter.set(response);
      }
    });
  };

  // Set initial location
  this.changeLocation('Montpellier');
});

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

Template.hello.events({
  'click .btn'(evt, instance) {
    instance.changeLocation('Nimes');
  },
});

Your server method:

import { Meteor } from 'meteor/meteor';

Meteor.methods({
  sendData(city) {
    const weatherman = require('weatherman.io');
    const cities = {
      'Montpellier': {
        latitude: 43.6109200,
        longitude: 3.8772300,
      },
      'Nîmes': {
        latitude: 43.8333300,
        longitude: 4.3500000,
      },
    };

    console.log(cities[city].latitude);

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

    const alRoker = new weatherman('db0ee89a0f17a93af5b7556eaf28db18', options);
    const forecastOptions = {
      latitude: cities[city].latitude,
      longitude: cities[city].longitude,
    };

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

    const weatherReport = Async(forecastOptions);
    // console.log(weatherReport);
    return weatherReport;
  },
});

Notes:

  1. My eslint complains if I don’t use ES2015 syntax, so I refactored.
  2. I have a preference for making template calls to Meteor methods in the onCreated. My logic is “why should I wait for any DOM rendering before I have some data?”. In this example, it will likely only shave a couple of ms off the template render time - but you get the idea.
  3. Given that we want to make the same method call in the event handler, I scope the calling function (changeLocation) to the template instance.
  4. The test code you’ve put together here doesn’t (yet) need an onRendered.
  5. I made your server array into an object indexed by city and refactored this change back through to the client, so your users get to work with something more friendly.
  6. You don’t need to put Meteor methods in a Meteor.startup() - there is some anecdotal evidence that says you shouldn’t (I’ve never had an issue, but still…)