流星:暂停 UI 元素的反应性

Meteor: Pause reactivity on UI element

我正在使用 Meteor 反应框架来允许用户在 web gui 中编辑文本框,根据文本框上的任何更改更新数据库,并使用来自数据库的更新来更新文本框。

这会创建一个依赖循环,当我快速键入时,更新之间的延迟会破坏用户编写的文本。

我认为如何缓解这种情况是暂时停止从数据库更新到用户关注的任何对象。

我已经尝试了很多方法来做到这一点。这是我的模板:

<template name="valueEditor">
  <div class="list-item {{editingClass}}">
    <input type="text" value="{{value}}" placeholder="value">
  </div>
</template>

这里有帮手:

Template.valueEditor.helpers({
  value : function(){
    var state = ! Session.equals(EDITING_KEY, this._id);
    console.log("reactive state = " + state)
    var result = Objects.find({_id:this._id},{reactive:state}).fetch()[0].value;
    console.log("Database is emitting '" + result + "'back to the UI input!!!")
    return result;
  });

事件如下:

Template.valueEditor.events({

  'keydown input[type=text]': function(event) {
    console.log("You've pressed = " + String.fromCharCode(event.which));
    if (event.which === 27 || event.which === 13) {
      event.preventDefault();
      event.target.blur();
    }
  },

  'keyup input[type=text]': _.throttle(function(event) {
    console.log("saving '" + event.target.value + "' to database.");
    Objects.update(this._id, {$set: {value: event.target.value}});
  }, 300)

)};

这是输出(当我快速输入时):

"You've pressed = T"
"You've pressed = E" 
"You've pressed = S"
"saving 'tes' to database."
"You've pressed = T"
"You've pressed = I"
"reactive state = false"
"Database is emitting 'tes'back to the UI input!!!"
"You've pressed = N"
"saving 'tesn' to database."
"You've pressed = G"
"You've pressed =  "
"reactive state = false"
"Database is emitting 'tesn'back to the UI input!!!"
"saving 'tesn' to database."

我怎样才能使数据库不覆盖我打算在输入框中键入的文本???

在您的第二个按键事件中,执行超时并且仅每隔 x 秒或更长时间更新一次数据库。

我发现当用户编辑它时,我可以通过将 html 元素中已有的内容发回 html 元素来让元素停止从数据库更新。这是代码:

Template.objectTemplate.events({
  'focus input[type=text]': function(event) {
    Session.set(EDITING_VALUE, event.target.value);
    Session.set(EDITING_KEY, this._id);
  },
  'blur input[type=text]': function(event){
    if (Session.equals(EDITING_KEY, this._id))
    {
      Session.set(EDITING_KEY, null);
      Session.set(EDITING_VALUE, "");
    }
  },
  'keydown input[type=text]': function(event) {
    if (event.which === 27 || event.which === 13) {
      event.preventDefault();
      event.target.blur();
    }
  },
  'keyup input[type=text]': _.throttle(function(event) {
    Objects.update(this._id, {$set: {value: event.target.value}});
  }, 300),
});

Template.objectTemplate.helpers({
  value : function(){
    var x;
    if (Session.equals(EDITING_KEY, this._id))
      x = Session.get(EDITING_VALUE);
    else
      x = this.value;
    return x
  }

解决方案似乎是 Tracker.nonreactive(func) (docs) 或 Collection.find({}, {reactive: false}); 的某种形式。

有人讨论了同一个问题here at the Meteor.com forums and a quick one

当我理解得更好时(也许通过查看 Tracker Manual?),我会更新这个答案...