【问题标题】:Meteor reactivity on contenteditable div has an issue, how can I resolve?contenteditable div 上的流星反应有问题,我该如何解决?
【发布时间】:2014-09-10 22:37:01
【问题描述】:

我有一个带有关联按钮的 div,该按钮可以切换 div 内容可编辑的真假。

一旦 div 被编辑并且用户点击保存,我会抓取内部 html 并将其存储在流星中,如下所示:

Template.note.events
  'click #deleteNote': (e) ->
    currentNoteId = @_id
    Notes.remove currentNoteId, (error) ->
      if error
        Errors.throw('could not delete this note, contact support', false)
  'click #editNote': (e, t) ->
    note = t.find '.note-container'    
    classie.toggle t.find('.note'), 'focus'
    if t.$('.note').hasClass 'focus'
      $(e.target).text 'Save'
      editor.activate()
    else
      $(e.target).attr 'disabled'
      currentNoteId = @_id
      console.log note.innerHTML
      Notes.update currentNoteId,
        $set: 
          html: note.innerHTML
      , (error) ->
        if error
          console.log error
        editor.deactivate()
        $(e.target).text 'Edit'
        $(e.target).removeAttr 'disabled'

我注意到一个奇怪的错误。我知道这是由于 Meteors 的反应,因为如果我禁用笔记集合上的更新命令,这不会发生。

如果我编辑最后一行文本,或在内容末尾添加新行,Meteor 会自动更新 div,最后一行重复两次。但是,如果我刷新页面,正确的内容就会出现在笔记中。

所以数据库中的数据是最新的,但是由于反应性而在屏幕上呈现的内容并不能反映数据库中的内容。这是流星如何更新页面的错误。有什么解决办法吗?如果您需要更多信息,或者您觉得我的解释令人困惑,请告诉我。

更新

因此,如果我禁用反应性并使用服务器返回数据手动渲染模板并附加到 DOM,它就可以工作。所以这绝对是 Meteor 的反应性如何与 contenteditable div 一起工作的一个错误。

以下是手动插入的更新代码:

Template.note.events
  'click #deleteNote': (e, t) ->
    e.preventDefault()
    currentNoteId = @_id
    Notes.remove currentNoteId, (error) ->
      if error
        Errors.throw('could not delete this note, contact support', false)
      else
        t.__component__.dom.remove()
        return false
  'click #editNote': (e, t) ->
    note = t.find '.note-container'    
    classie.toggle t.find('.note'), 'focus'
    if t.$('.note').hasClass 'focus'
      $(e.target).text 'Save'
      editor.activate()
    else
      $(e.target).attr 'disabled'
      currentNoteId = @_id
      console.log note.innerHTML
      Notes.update currentNoteId,
        $set: 
          html: note.innerHTML
      , (error) ->
        if error
          console.log error
          Errors.throw('could not save this note, contact support', false)

        editor.deactivate()
        $(e.target).text 'Edit'
        $(e.target).removeAttr 'disabled'

更新 2

所以经过更多的测试,我已经更接近于理解这个问题了。问题在于 Meteor 反应性地更新了用户已经使用 contenteditable 功能更新的 div 内容。

所以用户编辑了一个 div 的内容,当用户完成并单击保存时,我抓取内容并将其保存到数据库中。 div 并不真正需要更新,因为用户已经更新了它并且我正在存储结果。但是由于流星的反应性,它认为它需要更新 div,但它这样做不正确。

所以问题在于 Meteor 响应式更新已经准确的 DOM 元素,因为更新是基于用户使用 contenteditable 功能编辑的内容。

【问题讨论】:

  • 你运行的是什么版本的流星?
  • 我运行的是 0.8.2 版
  • 我发现这是 Meteor 处理内容可编辑 div 的反应性方式的问题。在这里查看 github 问题:github.com/meteor/meteor/issues/1964

标签: meteor


【解决方案1】:

知道这个问题已经有一年多了,但这是我试图绕过这个问题的方法。

使用铁路由

Router.route('/myroute', {
    waitOn: function(){
        return [Meteor.subscribe('collection', {data:params})];
    },
    action: {
        var myObject = Collection.findOne();
        this.render('myTemplate', {
            data: function(){
                return myObject;
            }
        });  
    }
};

模板

<template name="panel-description">

    <b>Description</b>
    <div contenteditable data-name="description" class="can-edit">{{{ getDescription }}}</div>

</template>

帮手

Template.objectInfo.helpers({
    'getDescription': function(){
        if(typeof this.description !== 'undefined' && this.description !== null){
            return this.description;
        }
        else{
            return 'N/A';
        }
    },
});

模糊/焦点事件和相应的方法调用

Template.objectInfo.events({
    'focus .can-edit' : function(e){
        // Get the description of myObject in currentData() so we can later compare for changes
        e.currentTarget.setAttribute('data-content', Template.currentData().description);
    },
    'blur .can-edit' : function(e){
        // Afer blur, store the content of our element
        var newData = e.currentTarget.innerHTML;

        // Compare if new content is diferent than previous one we stored in data-content 
        // attribute. Only make the server call if data changes.
        if(e.currentTarget.getAttribute('data-content') != newData){

            // Clear the element
            e.currentTarget.innerHTML = '';

            // The call to update our DB field.
            Meteor.call('saveObjectDescription', Template.currentData()._id, newData, function(err){
                // callback for error/success feedback
            });
        };

    },
});

这有点 hacky,但可以解决问题。

路由执行后,返回myObject 描述的getDescription 助手。在模糊时,我们检查之前内容的变化(存储在具有焦点事件的属性中),如果有差异,则调用更新方法。

Meteor 将通过帮助程序立即返回值,但是为了避免重复内容问题,我们在调用之前清理了元素。

当 HTML 为空时元素闪烁一微秒,这有点粗糙,除此之外,它还有效。

PS:使用三方括号将帮助程序呈现为 HTML。

希望对您有所帮助。

【讨论】:

    【解决方案2】:

    这可能有用:https://github.com/meteor/meteor/issues/1964#issuecomment-57948734

    解决了我的问题,当文本输入 ny 用户附加在 Helper 变量之前。

    【讨论】:

      【解决方案3】:

      看到这个问题:https://github.com/meteor/meteor/issues/2328#issuecomment-49833061

      看起来 Meteor 可能不对此次更新负责。所以我们必须自己保存和更新插入符号。

      “你可以在保存内容可编辑内容时获取插入符号的位置并将其存储在数据库中。稍后你可以读取这个位置并将插入符号移动到适当的位置。你在谷歌文档等应用程序中有类似的情况,它们保存插入符号的位置每个用户并相应地显示它。”

      我在网上找到了最好的插入符号包来保存和更新插入符号的位置,Rangy:

      https://code.google.com/p/rangy/wiki/SelectionSaveRestoreModule

      真的很好用。我只是保存插入符号位置然后更新文档并在回调中恢复插入符号。

      【讨论】:

        猜你喜欢
        • 2020-06-24
        • 1970-01-01
        • 2015-06-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多