【问题标题】:Meteor JS: How do I insert a document into a collection, but only on the client-side?Meteor JS:如何将文档插入集合中,但只能在客户端?
【发布时间】:2014-01-16 09:31:42
【问题描述】:

我是 Meteor 的新手,我正在构建一个简单的应用程序来学习该框架。我正在构建的应用程序可让您在小猫的图像上放置文字。

期望的行为是这样的:

用户点击小猫的任意位置,会出现一个 contenteditable 元素,让用户输入文本。在元素外部单击可保存元素,并保持原位。

我遇到的问题:

如果我使用该应用程序打开了两个浏览器窗口,并且我在一个窗口中单击了一只小猫,则两个窗口中都会出现一个空白字段。理想情况下,空白字段只会出现在我单击的窗口上。一旦保存了一个单词,那么 in 应该在两个窗口中都可见。

我的问题:

有没有办法只在客户端将insert 文档添加到集合中,然后稍后使用upsert 将文档添加到服务器端集合?

这是我尝试过的:

我创建了一个只存在于客户端的存根方法,用于插入文档。这样做的问题是,当我单击图像时,一个空白字段会出现一瞬间,然后又消失了。

代码如下:

image-tags.js

if (Meteor.isClient) {
  var isEditing;

  Template.image.image_source = function () {
    return "http://placekitten.com/g/800/600";
  };

  Template.tag.rendered = function(){
    var tag = this.find('.tag');
    if (isEditing && !tag.innerText) {
      tag.focus();
    }
  }

  Template.image.events({
    'click img' : function (e) {
      if (isEditing) {
        isEditing = false;
      } else {
        isEditing = true;
        var mouseX = e.offsetX;
        var mouseY = e.offsetY;

        // Tags.insert({x:mouseX, y:mouseY});

        // Insert tag on the client-side only.
        // Upsert later when the field is not empty.
        Meteor.call('insertTag', {x:mouseX, y:mouseY});
      }
    },

    'click .tag' : function (e) {
      isEditing = true;
    },

    'blur .tag' : function (e) {
      var currentTagId = this._id;
      var text = e.target.innerText;

      if(text) {
        Tags.upsert(currentTagId, {$set: {name: text}});
      } else {
        Tags.remove(currentTagId);
      }
    }
  });

  Template.image.helpers({
    tags: function() {
      return Tags.find();
    }
  });

  // Define methods for the collections
  Meteor.methods({
    insertTag: function(attr) {
      Tags.insert({x:attr.x, y:attr.y});
    }
  });
}

// Collections
Tags = new Meteor.Collection('tags');

image-tags.html

<head>
  <title>Image Tagger</title>
</head>

<body>
  {{> image}}
</body>

<template name="image">
  <figure>
    <img src="{{image_source}}" />
    <figcaption class="tags">
        {{#each tags}}
          {{> tag}}
        {{/each}}
      </figcaption>
  </figure>
</template>


<template name="tag">
  <div class="tag" contenteditable style="left: {{x}}px; top: {{y}}px;">
    {{name}}
  </div>
</template>

【问题讨论】:

    标签: javascript collections meteor


    【解决方案1】:

    您应该将临时标签(可能还有您的isEditing var)存储在Session

    Session.set("isEditing", true);
    Session.set("newTag", {x:mouseX, y:mouseY});
    

    您还可以通过在初始化时传递null 而不是集合名称来创建本地集合。但是,Session 应该适用于您正在做的事情。以leaderboard 为例。

    编辑:

    <figcaption class="tags">
      {{#each tags}}
        {{> tag}}
      {{/each}}
      {{#with newTag}}
        {{> tag}}
      {{/with}}
    </figcaption>
    
    Template.image.newTag = function() {
      return Session.get("newTag");
    }
    

    【讨论】:

    • 谢谢,我刚刚查看了排行榜,但并没有真正理解您所说的“传递 null 而不是收藏”名称的意思。这是我的应用程序的最新版本:image-tagger.meteor.com。当您第一次单击小猫时,您可以观察应用程序的两个浏览器窗口中如何出现一个空白字段。如果我将临时标签信息存储在Session 中,当我在一个浏览器中单击图像时,如何让一个空白字段仍然出现?
    • 本地集合定义为var MyLocalCollection = new Meteor.Collection(null);。请参阅我的编辑以了解添加临时 Session 标记的可能方法。
    • 啊,我明白了,这个例子真的很有帮助。会试一试。谢谢!
    • 仔细观察,您的建议似乎是在用户单击图像之前在 DOM 中包含一个空标签,而不是之后。因此,点击事件应该显示/隐藏标签。当标签被保存时,标签元素会被“真实”的元素替换?
    • 如果您使用{{#with newTag}} 块,则在newTag 帮助程序返回除null/undefined 之外的其他内容之前,标签不会添加到DOM。因此,您在点击处理程序中执行 Session.set("newTag", {x:mouseX, y:mouseY}),然后在您希望临时标记 HTML 消失时执行 Session.set("newTag", null)
    【解决方案2】:

    如果您仅在客户端创建集合,则在断开连接时可能会遇到问题:您的新文档不会存储在服务器上。

    在我看来,最好的方法是在您的文档中设置一个属性“已发布”或“编辑”或“状态”(具有已发布/编辑/...的值)。 然后你的发布方法应该返回:

    1. 当前用户的所有文档
    2. 所有“已发布”或未处于“编辑”状态的文档

    当用户创建文档时,它存储在服务器上,但处于编辑状态。 然后当您保存时,您可以决定发布它,然后所有其他用户将在他们的订阅中收到该文档。

    希望替代解决方案对您有所帮助

    【讨论】:

      猜你喜欢
      • 2015-07-03
      • 2016-04-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-06-27
      • 2014-08-25
      • 1970-01-01
      • 2013-05-27
      相关资源
      最近更新 更多