Meteor JS: Как да вмъкна документ в колекция, но само от страна на клиента?

Нов съм в Meteor и създавам просто приложение, за да науча рамката. Приложението, което създавам, ви позволява да поставите думи върху изображение на коте.

Желаното поведение е следното:

Потребителят щраква където и да е върху котето и се появява елемент с възможност за редактиране на съдържание, позволяващ на потребителя да въвежда текст. Щракването извън елемента запазва елемента и той остава на мястото си.

Проблемът, с който се сблъсквам:

Ако имам два отворени прозореца на браузъра с приложението и щракна върху едно коте в един прозорец, празно поле се появява и в двата прозореца. В идеалния случай празното поле ще се появи само в прозореца, върху който съм щракнал. След като дадена дума бъде запазена, тогава 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>

person Chanpory    schedule 29.12.2013    source източник


Отговори (2)


Трябва да съхраните временния маркер (и вероятно вашия isEditing var) в Session:

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

Можете също така да създадете локална колекция, като подадете null вместо име на колекция, когато я инициализирате. Въпреки това, Session трябва да работи за това, което правите. Разгледайте таблата за пример.

Редактиране:

<figcaption class="tags">
  {{#each tags}}
    {{> tag}}
  {{/each}}
  {{#with newTag}}
    {{> tag}}
  {{/with}}
</figcaption>

Template.image.newTag = function() {
  return Session.get("newTag");
}
person sbking    schedule 29.12.2013
comment
Благодаря, току-що проверих класацията, но наистина не разбирам какво имате предвид, като подадете null вместо името на колекцията. Ето най-новата версия на приложението ми: image-tagger.meteor.com. Можете да наблюдавате как се появява празно поле и в двата прозореца на браузъра на приложението, когато щракнете за първи път върху котето. Ако съхраня информацията за временния етикет в Session, как ще накарам празно поле да продължава да се показва, когато щракна върху изображение, само в един браузър? - person Chanpory; 29.12.2013
comment
Локална колекция се дефинира като var MyLocalCollection = new Meteor.Collection(null);. Вижте моята редакция за възможен начин за добавяне на временния маркер Session. - person sbking; 29.12.2013
comment
Виждам, този пример наистина помага. Ще го пробвам. Благодаря ти! - person Chanpory; 29.12.2013
comment
Ако се вгледаме по-внимателно, изглежда, че това, което предлагате, е включване на празен таг в DOM, преди потребителят да щракне върху изображението, вместо след това. Следователно събитието за кликване трябва да показва/скрива маркера. И когато етикетът бъде запазен, елементът на етикета ще бъде заменен с истинския? - person Chanpory; 29.12.2013
comment
Ако използвате блок {{#with newTag}}, етикетът няма да бъде добавен към DOM, докато помощникът newTag не върне нещо различно от null/undefined. Така че правите Session.set("newTag", {x:mouseX, y:mouseY}) в манипулатора на кликванията и след това правете Session.set("newTag", null), когато искате временният HTML етикет да изчезне. - person sbking; 29.12.2013

Ако създадете колекцията само от страна на клиента, може да имате проблем, ако връзката ви е прекъсната: новите ви документи няма да се съхраняват на сървъра.

Според мен най-добрият начин е да зададете свойство "публикуван", "редактиране" или "статус" (със стойност публикуван / eiditing / ...) във вашия документ. Тогава вашите методи за публикуване трябва да върнат:

  1. Всички документи на текущия потребител
  2. Всички документи са „публикувани“ или не са в състояние „редактиране“.

Когато потребител създаде документ, той се съхранява на сървъра, но със статус на редактиране. тогава, когато запазите, можете да решите да го публикувате и тогава всички останали потребители ще получат документа в техния абонамент.

Надяваме се, че алтернативното решение ще ви помогне

person Rebolon    schedule 08.01.2014