【问题标题】:Subscription reactive on Session changes causes #each to redraw every entity对会话更改的订阅反应导致#each 重绘每个实体
【发布时间】:2014-12-03 22:30:28
【问题描述】:

所以这里有一个问题:我使用this neat solution 存储用户的坐标。这是我的实现:

updateLoc = function () {
    var position = Geolocation.latLng() || {lat:0,lng:0};
    Session.set('lat', position.lat);
    Session.set('lon', position.lng);
};

Meteor.startup(function() {
    updateLoc(); // set at 0, 0 to begin with
    Meteor.setTimeout(updateLoc, 1000); // get first coordinates 1 second in
    Meteor.setInterval(updateLoc, 5000); // then, every 5 seconds
});

根据这两个会话变量,我有一个 entitiesList 路由等待实体被订阅:

this.route('entitiesList', {
    path: '/',
    waitOn: function() {
        if (Meteor.userId())
            return Meteor.subscribe('entities', {lat: Session.get('lat'),lon: Session.get('lon')});
    },
    data: function() {
        return {entities: Entities.find()};
    }
});

这是出版物:

Meteor.publish('entities', function (position) {
    if (position.lon !== null && position.lat !== null) {
        return Entities.find({location: {
            $near: {$geometry:{type: "Point", coordinates: [position.lon, position.lat]},$maxDistance:500}}
        }});
    }
    this.ready();
});

最后是entitiesList模板:

<template name="entitiesList">
  <div class="entities">
    <h1>Entities list</h1>
    {{#each entities}}
      {{> entityItem}}
    {{else}}
        <p>No entity found. Looking up...</p>
        {{>spinner}}
    {{/each}}
  </div>
</template>

现在!此解决方案有效。实体已正确列出,根据用户的位置每 5 秒更新一次。

唯一的问题在于渲染:当响应是由于 Session 变量的更新,整个实体集被删除并重绘。但是当实体集合中发生更改(例如,删除/创建实体)时,只会在模板中相应地重新呈现此更改。

这会产生一个非常烦人的列表,每 5 秒闪烁一次。我想删除#each 块并在模板的rendered 函数中使用this.autorun() 自己编写它,并使用jQuery 以更优化的方式重绘列表,但这将是一个令人讨厌的黑客,使用模板文件之外的 HTML 代码块...肯定有另一种方法!

【问题讨论】:

    标签: session meteor reactive-programming


    【解决方案1】:

    每次您更改会话变量时,您的订阅都会加载,Iron Router 会设置他的加载模板,这就是它闪烁的原因。

    您可以这样做,而不是使用 Iron-router:

    Template.entitiesList.created=function()
    {
        var self=this
        this.isLoading=new ReactiveVar(false)
        this.isFirstLoading=new ReactiveVar(true)
        this.autorun(function(){
    
            self.isLoading.set(true)
            Meteor.subscribe('entities', {lat: Session.get('lat'),lon: Session.get('lon')},function(err){
                self.isLoading.set(false)
                self.isFirstLoading.set(false)
            });
        })
    }
    Template.entitiesList.helpers({
        entities:function(){return Entities.find()}
        isLoading:function(){Template.instance().isLoading.get()
        isFirstLoading:function(){Template.instance().isFirstLoading.get()
    })
    
    
    <template name="entitiesList">
      <div class="entities">
        <h1>Entities list</h1>
        {{#if isFirstLoading}}
           <p>Looking up...<p/>
           {{>spinner}}
        {{else}}
            {{#each entities}}
                {{> entityItem}}
            {{else}}
                <p>No entity found</p>
            {{/each}}
            {{#if isLoading}}
                {{>spinner}}
            {{/if}}
        {{/if}}
      </div>
    </template>
    

    【讨论】:

    • 非常感谢!正是我要找的东西:一个干净的 hack :) 我刚刚在 each 块中添加了一个 else 语句,以便在该区域中找不到实体时显示通知。
    【解决方案2】:

    在使用 Iron-router 时,我发现实际上有一个选项可以在每个触发的新订阅上不呈现加载模板:the subscriptions option。只需将waitOn 替换为subscriptions 即可获得所需的结果。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-10-13
      • 2022-11-28
      • 2015-11-03
      • 2014-11-11
      • 1970-01-01
      • 2012-08-23
      • 1970-01-01
      相关资源
      最近更新 更多