流星:自动运行不会使我的代码动态化
Meteor : autorun won't make my code dynamic
我正在努力开发一个 meteor 应用程序,其目标是在 google 地图上动态显示车辆的路径,例如海上的一艘船。
现在,我看到这个名为 gmaps.js 的库,并且由于它在 npm 上可用(就像 google 地图 api)我决定使用它作为绘制的解决方案地图的。
所以,我有一个页面,每次我点击一个按钮时都会在数据库中添加一个地理位置(/runs/send)(这足以进行测试)。然后,在我的另一个页面 (/runs/show) 上,目标是从 mongo 获取数据并在地图上动态提示它(意思是,如果我通过按下按钮添加数据,我会看到新路径出现在地图上)。这是代码现在的样子:
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
});
});
});
});
});
因此,如您所见,我将我的 onCreated 函数放在一个自动运行块中,我使用的数据来自数据库,所以它是一个游标,所以它也应该是反应式的。
在反应性代码块中使用反应性数据(感谢自动运行)?当我在第二页中按 "send" 时,我希望在屏幕上看到一个新行(此页面只是将一组新的 [x,y] 添加到 run.positions),但是....没有什么 !事实上,如果我手动重新加载页面,当然会出现新行,但是好吧...老实说,这不是我想要的...
就是这样!知道为了获得真正的反应性而缺少什么吗?
编辑:
这段代码部分工作:我第一次加载页面时,console.log(map) 给出了一个未定义的,但我只需要重新加载一次,然后页面就会完全按预期工作,显示我想要的是动态的。然而,一个单一的代码重新加载,然后 console.log(map) 再次给出未定义的,我需要一个新的 F5...。知道它为什么这样做/如何解决它吗?
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();
});
});
});
});
(在这个新代码中,我只是在加载 gmaps 时在 onCreated 中创建地图,然后,我在 onRendered 中绘制所有图形。顺便说一句,我使用 Template.xxx.map 来传输数据在 onCreated 和 onRendered 之间,这是我应该做的吗?)
问题似乎在于订阅回调不是反应式上下文。尝试做对其他人有用的事情 here and ,以及将跟踪放在您的 onRendered 中。
Template.templateName.onRendered(function() {
var self = this;
self.autorun(function() {
self.subscribe('allRuns',function() {
Tracker.autorun(function(){
...
}
})
})
})
为此尝试使用嵌套模板。以便您的包装器模板订阅数据并仅在订阅准备就绪时呈现嵌套模板:
//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>
P.S。这主要是伪代码,因为我从未测试过它,所以仅将其用作指南
我正在努力开发一个 meteor 应用程序,其目标是在 google 地图上动态显示车辆的路径,例如海上的一艘船。
现在,我看到这个名为 gmaps.js 的库,并且由于它在 npm 上可用(就像 google 地图 api)我决定使用它作为绘制的解决方案地图的。
所以,我有一个页面,每次我点击一个按钮时都会在数据库中添加一个地理位置(/runs/send)(这足以进行测试)。然后,在我的另一个页面 (/runs/show) 上,目标是从 mongo 获取数据并在地图上动态提示它(意思是,如果我通过按下按钮添加数据,我会看到新路径出现在地图上)。这是代码现在的样子:
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
});
});
});
});
});
因此,如您所见,我将我的 onCreated 函数放在一个自动运行块中,我使用的数据来自数据库,所以它是一个游标,所以它也应该是反应式的。
在反应性代码块中使用反应性数据(感谢自动运行)?当我在第二页中按 "send" 时,我希望在屏幕上看到一个新行(此页面只是将一组新的 [x,y] 添加到 run.positions),但是....没有什么 !事实上,如果我手动重新加载页面,当然会出现新行,但是好吧...老实说,这不是我想要的...
就是这样!知道为了获得真正的反应性而缺少什么吗?
编辑:
这段代码部分工作:我第一次加载页面时,console.log(map) 给出了一个未定义的,但我只需要重新加载一次,然后页面就会完全按预期工作,显示我想要的是动态的。然而,一个单一的代码重新加载,然后 console.log(map) 再次给出未定义的,我需要一个新的 F5...。知道它为什么这样做/如何解决它吗?
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();
});
});
});
});
(在这个新代码中,我只是在加载 gmaps 时在 onCreated 中创建地图,然后,我在 onRendered 中绘制所有图形。顺便说一句,我使用 Template.xxx.map 来传输数据在 onCreated 和 onRendered 之间,这是我应该做的吗?)
问题似乎在于订阅回调不是反应式上下文。尝试做对其他人有用的事情 here and
Template.templateName.onRendered(function() {
var self = this;
self.autorun(function() {
self.subscribe('allRuns',function() {
Tracker.autorun(function(){
...
}
})
})
})
为此尝试使用嵌套模板。以便您的包装器模板订阅数据并仅在订阅准备就绪时呈现嵌套模板:
//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>
P.S。这主要是伪代码,因为我从未测试过它,所以仅将其用作指南