对于可信任的div的流星反应有一个问题,我该如何解决?

时间:2014-07-20 06:06:26

标签: meteor

我有一个带有关联按钮的div,可以切换divs contenteditable true和false。

enter image description here

一旦编辑了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的反应性,因为如果我在notes集合上禁用更新命令,则不会发生这种情况。

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

因此数据在数据库中是最新的,但由于反应性而在屏幕上呈现的内容并不反映数据库中的内容。这是meteor如何更新页面的错误。对此有何解决方案?如果您需要更多信息,或者如果您发现我的解释令人困惑,请告诉我。

更新

因此,如果我禁用反应性并使用服务器返回数据手动呈现模板并附加到DOM,则可以正常工作。所以这绝对是Meteor的反应性如何与可信的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功能编辑的内容。

3 个答案:

答案 0 :(得分:1)

请参阅此问题:https://github.com/meteor/meteor/issues/2328#issuecomment-49833061

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

"在保存可信内容并将其存储在数据库中时,您可以获得carret的位置。稍后您可以阅读此位置并将插入符号移动到适当的位置。您在Google Docs这样的应用程序中也有类似的情况,它们会保留每个用户的插入位置并相应地显示它。"

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

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

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

答案 1 :(得分:1)

知道这个问题已经过了一年多了但是我在这里试图绕过这个问题。

使用铁路由器

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

Le 模板

<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,但是诀窍。

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

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

当HTML为空时,闪烁一微秒的元素有点粗糙,除此之外,它还可以工作。

PS:使用三重括号将帮助器呈现为HTML。

希望有所帮助。

答案 2 :(得分:0)

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

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