I'm working hard on a meteor App which goal is to dynamically display on a google map the path of a vehicle, for example a boat on the sea.
Now, I see this library called gmaps.js , and since it is available on npm (just like google maps api) I decide to use this as a solution to draw of the map.
So, I have one page that add a geographic position (/runs/send) in the database each time I click on a button (this is enougth for testing). Then, on my other page (/runs/show) the goal is to get that data from mongo and prompt it dynamically on the map (meaning, if I add data by pressing the button, I'll see the new path appear on the map). Here is what the code looks like for now :
import { Template } from 'meteor/templating';
import {Tracker} from 'meteor/tracker';
import { Meteor } from 'meteor/meteor'
import gmaps from 'gmaps';
import google_maps from 'google-maps';
import {Mongo} from 'meteor/mongo';
import {Run} from './run.js';
import './methods.js';
Template.runs_show.helpers({
all() {
return Run.find({});
}
});
Template.runs_show.onCreated(function() {
var self = this;
self.autorun(function() {
self.subscribe('allRuns',function() {
google_maps.KEY = "MY API KEY";
google_maps.load(function(google){
console.log("Google Maps loaded");
// this creates a new map
var map = new gmaps({
el: '#map-gmaps',
lat: -12.043333,
lng: -77.028333
});
// for now , the data is on the run with {"maxSpeed" : "75"}
var dada = Run.findOne({"maxSpeed" : "75"});
// path look like [[x1,y1],[x2,y2]]
var path = dada.positions;
// this draws a red line on the map following the points defined in path
map.drawPolyline({
path: path,
strokeColor: '#FC291C',
strokeOpacity: 0.85,
strokeWeight: 6
});
});
});
});
});
So, as you can see, I put my onCreated function in a autorun block, and the data i'm using is from a database, so it's a cursor, so it should be reactive as well.
With a reactive data, inside a reactive block of code (thanks autorun)? expected to see a new line appear on my screen when I press "send" in my second page (this page just add a new set of [x,y] to the run.positions), but.... Nothing ! In fact, If I reload the page manually, the new line appears, of course, but wellll... That's not what I wanted to be honest...
So that's it! any idea what is missing in order to have some true reactivity?
EDIT :
This code works partially : the first time I load the page, the console.log(map) gives a undefined, but I just need to reload once, and then the page will work exactly as intended, showing what I want dynamically. However, one single code reload, and then, again, the console.log(map) gives undefined, and I need a new F5.... Any idea on why it does that / how to solve it?
Template.runs_show.onCreated(function() {
google_maps.KEY = "MY API KEY";
google_maps.load(function(google){
var map = new gmaps({
el: '#map-gmaps',
lat: -12.043333,
lng: -77.028333
});
// with that, I can use the map in the onRendered
Template.runs_show.map = map;
});
console.log(Template.runs_show);
});
Template.runs_show.onRendered(function() {
var self = this;
self.autorun(function() {
self.subscribe('allRuns',function() {
Tracker.autorun(function(){
var map = Template.runs_show.map;
console.log(map);
var dada = Run.findOne({"maxSpeed" : "75"});
var path = dada.positions;
map.drawPolyline({
path: path,
strokeColor: '#FC291C',
strokeOpacity: 0.85,
strokeWeight: 6
});
// seems to not be necesary
//map.refresh();
});
});
});
});
(in this new code, I just create the map in the onCreated, when the gmaps is loaded, and then, I make all the drawing in the onRendered. Btw, I used Template.xxx.map to transmit data between onCreated and onRendered, is that what i'm supposed to do?)
Seems the issue is that the subscribe callback is not a reactive context. Try doing what worked for others here and here , as well as putting the tracking in your onRendered.
Template.templateName.onRendered(function() {
var self = this;
self.autorun(function() {
self.subscribe('allRuns',function() {
Tracker.autorun(function(){
...
}
})
})
})
Try using nested templates for this. So that your wrapper template subscribes to data and only renders nested template when subscriptions is ready:
//wrapper template that manages subscription
Template.wrapper.onCreated(function() {
this.subscribe('allRuns');
});
Template.runs_show.onRendered(function() {
google_maps.KEY = "MY API KEY";
google_maps.load(function(google){
var map = new gmaps({
el: '#map-gmaps',
lat: -12.043333,
lng: -77.028333
});
Tracker.autorun(function() {
// Run.find will re-trigger this whole autorun block
// if any of the elements of the collection gets changed or
// element gets created or deleted from collection
// thus making this block reactive to data changes
// this will also work with findOne in case you only want to
// one run only
var runs = Run.find({"maxSpeed" : "75"}).fetch();
// map.clear() or something like that to remove all polylines
// before re-rendering them
runs.forEach(function(run){
map.drawPolyline({
path : path,
strokeColor : '#FC291C',
strokeOpacity : 0.85,
strokeWeight : 6
});
});
});
// ^^ this is pretty dumb and re-renders all items every time
// something more intelligent will only re-render actually
// changed items and don't touch those who didn't change but
// that will require a slightly more complex logic
});
});
wrapper.html:
<template name="wrapper">
{{#if Template.subscriptionsReady }}
{{> runs_show }}
{{/if}}
</template>
PS this is mostly pseudo code since I never tested it, so just use it as a guide
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.