Meteor Blaze通过子文档属性

时间:2016-06-07 18:03:41

标签: javascript arrays sorting meteor reactive-programming

资料:

_id: Pe0t3K8GG8,
videos: [
   {id:'HdaZ8rDAmy', url:'VIDURL', rank: 2},
   {id:'22vZ8mj9my', url:'VIDURL2', rank: 0},
   {id:'8hyTlk8H^6', url:'VIDURL3', rank: 1},
]

配置文件与视频列表一起显示。我有一个Drag&使用服务器方法删除更新视频排名。

1)数据库在 Drop 上正确更新。

2)对视频阵列进行排序 - 我基于个人资料模板和 SORT 视频阵列上声明帮助者>自定义比较功能。

Template.Profile.helpers({
    'videosSorted': function(){
        let videos = (this.videos);
        let videosSorted = videos.sort(function(a, b) {
        return parseFloat(a.rank) - parseFloat(b.rank);
    });
    return videosSorted;
  }
});

问题:

A)在Blaze中,{{#each videosSorted}}不会被动反应更新。 如果我F5刷新,那么我可以看到新订单。

我认为问题是因为我提供的 videosSorted 不会更新数据库中文档的更改。

如何将 videosSorted 反应?

更新

所有相关代码: 铁路由器控制器 - 我订阅并设置布局的数据上下文

ProfileController = RouteController.extend({
 subscriptions: function() {
    this.subscribe('profile',this.params.slug).wait();
  },
  data: function () {
     //getting the data from the subscribed collection
     return Profiles.findOne({'slug':this.params.slug});
  },
})

公开:

Meteor.publish('profile', function (slug) {
  const profile = Profiles.find({"slug":slug});
  if(profile){
    return profile;
  }
  this.ready();
});

个人资料HTML模板:

<template name="Profile">
     <ul  class="sortlist">
        {{#each videosSorted}}
            {{> Video}}
        {{/each}}
     </ul>
</template>

我正在使用 mrt:jquery-ui - 可排序函数

Template.Profile.onRendered(function () {
  thisTemplate = this;

  this.$('.sortlist').sortable({
    stop: function(e, ui) {

      el = ui.item.get(0);
      before = ui.item.prev().get(0);
      after = ui.item.next().get(0);

      if(!before) {
        newRank = Blaze.getData(after).rank - 1
      } else if(!after) {
        newRank = Blaze.getData(before).rank + 1
      }
      else {
        newRank = (Blaze.getData(after).rank +
          Blaze.getData(before).rank) / 2
      }

      let queryData = {
          _id: thisTemplate.data._id,    //the id of the profile record
          videos_objId: Blaze.getData(el).objId,    //the id of the sub document to update
          new_rank: newRank  //the new rank to give it
      };

      //Update the sub document using a server side call for validation + security  
      Meteor.call("updateVideoPosition", queryData, function (error, result) {
          if(!result){
            console.log("Not updated");
          }
          else{
            console.log("successfully updated Individual's Video Position")
          }
      });
   }
 })
});

最后是进行更新的Meteor方法

'updateVideoPosition': function (queryData){
    let result = Individuals.update(
      {_id: queryData._id, 'videos.objId': queryData.videos_objId },
      { $set:{ 'videos.$.rank' : queryData.new_rank } }
    )
    return result;
  }

注意:

正如我所提到的 - 数据库正确更新 - 如果我有一个隐身窗口打开到同一页面 - 我会看到视频重新激活(神奇地!)切换到新订单。

架构

const ProfileSchema = new SimpleSchema({
  name:{
    type: String,
  }
  videos: {
    type: [Object],
    optional:true,
  },
  'videos.$.url':{
    type:String,
  },
  'videos.$.rank':{
    type:Number,
    decimal:true,
    optional:true,
    autoform: {
      type: "hidden",
    }
  },
  'videos.$.subCollectionName':{
    type:String,
    optional:true,
    autoform: {
      type: "hidden",
    }
  },
  'videos.$.objId':{
    type:String,
    optional:true,
    autoform: {
      type: "hidden",
    }
  } 
});

1 个答案:

答案 0 :(得分:2)

我想出了非常粗糙的解决方案,但我现在还没有看到其他选择。我能想到的最简单的解决方案是手动重新呈现模板:

Template.Profile.onRendered(function () {
  var self = this;
  var renderedListView;
  this.autorun(function () {
    var data = Template.currentData(); // depend on tmeplate data
    //rerender video list manually
    if (renderedListView) {
      Blaze.remove(renderedListView);
    }
    if (data) {
      renderedListView = Blaze.renderWithData(Template.VideoList, data, self.$('.videos-container')[0]);
    }
  });
});
Template.VideoList.onRendered(function () {
  var tmpl = this;
  tmpl.$('.sortlist').sortable({
    stop: function (e, ui) {
      var el = ui.item.get(0);
      var before = ui.item.prev().get(0);
      var after = ui.item.next().get(0);
      var newRank;
      if (!before) {
        newRank = Blaze.getData(after).rank - 1
      } else if (!after) {
        newRank = Blaze.getData(before).rank + 1
      }
      else {
        newRank = (Blaze.getData(after).rank +
          Blaze.getData(before).rank) / 2
      }
      let queryData = {
        _id: tmpl.data._id,    //the id of the profile record
        videos_objId: Blaze.getData(el).objId,    //the id of the sub document to update
        new_rank: newRank  //the new rank to give it
      };
      //Update the sub document using a server side call for validation + security
      Meteor.call("updateVideoPosition", queryData, function (error, result) {
        if (!result) {
          console.log("Not updated");
        }
        else {
          console.log("successfully updated Individual's Video Position")
        }
      });
    }
  });
});
Template.VideoList.helpers({
  videosSorted: function () {
    return this.videos.sort(function (a, b) {
      return a.rank - b.rank;
    });
  }
});

和HTML:

<template name="Profile">
  <div class="videos-container"></div>
</template>

<template name="VideoList">
  <ul class="sortlist">
    {{#each videosSorted}}
      <li>{{url}}</li>
    {{/each}}
  </ul>
</template>

由于JQuery UI Sortable,在您的案例中失去了Reativeness。它对Meteor的反应性一无所知,只是阻止模板重新渲染。

可能你应该考虑使用像this这样更流行的Meteor(我不确定它是否适合你的需要)。