javascript - Meteor Blaze 按子文档属性排序子文档

标签 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},
]

配置文件与视频列表一起显示。我有一个拖放功能,它使用服务器方法更新视频排名。

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

2) 对视频数组进行排序 - 我在配置文件模板上声明了一个助手,并根据视频数组排序>自定义比较功能

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 具有响应性?

更新:

所有相关代码: Iron Router Controller - 我订阅并设置布局的数据上下文

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

注意:

正如我提到的 - 数据库更新正确 - 如果我有一个打开到同一页面的隐身窗口 - 我看到视频 reactivly(神奇地!)切换到新顺序。

模式

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

最佳答案

我想出了一个非常粗略的解决方案,但我现在看不到其他选择。我能想到的最简单的解决方案是手动重新渲染模板:

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,您的案例失去了 react 性。它对 Meteor 的 react 性一无所知,只是阻止模板重新渲染。

也许你应该考虑使用更适合 Meteor 的东西,比如 this (我不确定它是否符合您的需求)。

关于javascript - Meteor Blaze 按子文档属性排序子文档,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37686293/

相关文章:

php - 在 symfony2 Controller 中使用 usort 和关联数组

javascript - orderBy,第一个应该是最旧的,剩下的是最新的

java - 如何从字符串中删除(字母和特殊)字符并将其存储到一个数组?

javascript - Switch 语句 jQuery 不适用于单选按钮值

javascript - 如何使用 new Date() 解析 JSON 字符串并获取对象中的 Date 属性?

ruby-on-rails - 如果键相等,如何将哈希数组分成不同的数组?

javascript - 有没有办法在联合类型上调用数组原型(prototype)方法?

javascript - IE11 中的第一个 Fetch API 调用被第二个取消

javascript - 当输入字段从复选框中隐藏时,如何使 ng-model 预览数据为空?

python - 使用 Pyperclip 复制和粘贴二维数组