订阅集合中但不在模板中的更改 [英] Subscribing to changes in a Collection but not in a template

查看:26
本文介绍了订阅集合中但不在模板中的更改的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我对meteor 很陌生,如果我在这里遗漏了一些非常基本的东西,我深表歉意.

I'm very new to meteor, so apologies if I'm missing something very basic here.

我认为创建一个非常简单的 textpad 风格的应用程序来检查流星会很有趣.我使用待办事项应用程序并将数据结构更改为文件夹"和文档"而不是列表"和待办事项",因此我有一个文件夹列表,当您单击该文件夹时,您将获得一个文档列表在那个文件夹中.

I thought it would be fun to create a very simple textpad style app to check out meteor. I took the todo app and changed the data structures to be 'folders' and 'docs' rather than 'lists' and 'todos', so I have a list of folders and when you click on the folder you get a list of the documents in that folder.

然后,我添加了一些代码来在单击列表中的一个文档时显示单个文档"的内容"属性.

I've then added some code to show the 'content' attribute of a single 'doc' when one of the docs in the list is clicked.

我正在使用 ace 为文档的内容添加一些漂亮的打印(https://github.com/ajaxorg/ace).我已将 ace 设置为使用包含我的文档的纯文本版本的隐藏文本区域,并且编辑器对象获取此文本并对其进行漂亮的打印.

I'm using ace to add some pretty print to the content of the doc (https://github.com/ajaxorg/ace). I've set ace up to work with a hidden textarea containing the plaintext version of my document, and the editor object takes this text and pretty prints it.

ace 的问题是,我不希望每次文档内容更改时都替换包含 ace 编辑器的模板(因为重新初始化需要半秒钟,这在每个字符之后都是糟糕的体验)打字!).相反,我想更新 textarea 模板,然后使用 ace API 告诉编辑器根据 textarea 中的内容更新它的输入.

The problem with ace is that I don't want the template containing the ace editor to be replaced every time the contents of the doc changes (as it takes half a second to reinitialise, which is a crappy experience after every character is typed!). Instead, I want to update the textarea template and then use the ace API to tell the editor to update it's input based on what is in the textarea.

现在,这可能是解决问题的错误方法,但我最终使用了两个模板.第一个包含一个包含 doc.contents 的 textarea,它是对底层模型的反应:

Now, this is probably the wrong way to approach the problem, but I've ended up using two templates. The first contains a textarea containing doc.contents, which is reactive to the underlying model:

<template name="doc_content">
  <textarea name="editor">{{content}}</textarea>
</template>

第二个包含 'editor' div,ace 用它来显示漂亮的打印文本.

The second one contains the 'editor' div which ace uses to display the pretty printed text.

<template name="doc_init">
  <div id="editor"></div>
</template> 

我们的想法是,每次用户键入时(在所有客户端上)第一个模板都会更新,而第二个模板只会为我们加载的每个新文档重新加载.

The idea is that the first template will update every time the user types (on all clients), and the second template is only ever re-loaded for each new doc we load.

Template.doc_content.content = function() {
  var doc_id = Session.get('viewing_itemname');
  if (!doc_id) {
    return {}; 
  }

  var doc = Docs.findOne({_id:doc_id});
  if (doc && doc.content) {
    // #1 Later
    var editor = Session.get('editor');
    if (editor) {
      editor.getSession().setValue(doc.content);
    }   

    return doc.content;
  } else {
    return ''; 
  }
};

当您在编辑器 div 中输入文本时,我会调用 Docs.update(doc_id, {$set: {content: text}});,它会更新 textarea 中的值每个客户.到目前为止一切都很好.

When you enter text into the editor div I make a call to Docs.update(doc_id, {$set: {content: text}});, which updates the value in the textarea on each client. All good so far.

editor.getSession().on('change', function(){
    var text = editor.getSession().getValue();
    Docs.update(doc_id, {$set: {content: text}});
});

对于除进行更改的客户端之外的所有客户端,我想要做的是订阅该文档的更改并使用刚刚更改的文本调用 editor.getSession().setContent(),从 textarea 中取出文本并用它填充编辑器.

What I want to do, for all clients other than the client which made the change, is to subscribe to the change for that doc and call editor.getSession().setContent() with the text which has just been changed, taking the text from the textarea and using it to fill the editor.

我尝试通过从包含 textarea 的模板进行调用来做到这一点(因为每当文档更新时都会发生变化 - 请参阅上面的 #1).但是,这会使客户端陷入无限循环,因为更改编辑器中的值会导致再次调用 Docs.update.

I've tried to do this by making that call from the template containing the textarea (as this changes whenever the doc is updated - see #1 above). However, this puts the clients into an infinite loop because changing the value in the editor causes another call to Docs.update.

显然,当您渲染模板时不会发生这种情况,所以我假设流星中有一些魔法可以防止这种情况发生,但我不确定如何.

Obviously this doesn't happen when you render a template, so I'm assuming there's some magic in meteor which can prevent this happening, but I'm not sure how.

有什么想法吗?

TIA!

推荐答案

你的问题有很多东西需要吸收,但如果我理解正确,你可能只是在追求 Deps.autorun:>

There's a lot to absorb in your question, but if I understand correctly, you might simply be after Deps.autorun:

Deps.autorun(function () {
    var doc_id = Session.get('viewing_itemname');
    if (!doc_id) {
        return {};
    }

    var doc = Docs.findOne({_id:doc_id});

    // do stuff with doc
});

Deps.autorun 非常有用,因为它会重新运行依赖项改变.这些依赖项仅限于那些反应性"例如集合和会话,或任何实现反应式 API 的东西.

Deps.autorun is really useful in that it will get re-run if any of its dependencies change. These dependencies are limited to those that are "reactive" such as Collections and Sessions, or anything that implements the reactive API.

在您的情况下,Session.getfindOne 都是反应性的,因此如果它们的值完全改变,Deps.autorun 将再次运行该函数.

In your case, both Session.get and findOne are reactive so if their values change at all, Deps.autorun will run the function again.

这篇关于订阅集合中但不在模板中的更改的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆