Meteor: «Ошибка типа: неопределенный не является объектом» при использовании коллекции

#javascript #meteor

#javascript #meteor

Вопрос:

Я просто пробую Meteor, и я, в общем, тоже не очень продвинут в Javascript. Я пытаюсь отобразить текстовое свойство объекта из коллекции на стороне клиента, используя шаблон, но я получаю ошибку, упомянутую в названии. Я просто немного изменил базовый проект Meteor по умолчанию.

main.html:

 <head>
  <title>Test</title>
</head>

<body>
  <section>
    {{> tweet}}
  </section>
</body>

<template name="tweet">
  <h1 class="mt-5">{{text}}</h1>
</template>
  

main.js

 import { Template } from 'meteor/templating';
import { ReactiveVar } from 'meteor/reactive-var';

import './main.html';
import 'bootstrap/dist/js/bootstrap.bundle';

Tweets = new Mongo.Collection('tweets');

Template.tweet.onCreated(function tweetOnCreated() {
  var txt = Tweets.findOne().text;
  this.text = new ReactiveVar(txt);
});

Template.tweet.helpers({
  text() {
    return Template.instance().text.get();
  },
});
  

Что не так с var txt = Tweets.findOne().text; ? У меня здесь общее непонимание Javascript или эта ошибка каким-то образом связана с тем, как работает Meteor?

Ответ №1:

Это связано с тем, как работает Meteor.

Когда клиент запускается, у него еще нет никаких данных. Затем клиент открывает подписки на сервере (при условии, что у вас все еще установлен пакет автоматической публикации по умолчанию, это делается для вас), которые вскоре после этого отправляются через данные.

Именно эта часть «вскоре после» является проблемой здесь.

В вашем случае это означает, что при Tweets.findOne() запуске у него еще нет данных, и поэтому нет документа для чтения text . Таким образом, ошибка. Предотвратите ошибку, проверив, был ли возвращен документ:

 Template.tweet.onCreated(function () {
  var doc = Tweets.findOne();
  if (doc) {
    this.text = new ReactiveVar(doc.text);
  }
});
  

Если вы попробуете это, ошибка исчезнет, но текст по-прежнему не отображается.

Итак, теперь мы хотим, чтобы этот раздел кода запускался снова, когда данные будут доступны. Blaze делает это автоматически в помощниках, но везде еще вам нужно обернуть это в autorun :

 Template.tweet.onCreated(function () {
  this.text = new ReactiveVar();
  this.autorun(() => {
    var doc = Tweets.findOne();
    if (doc) {
      this.text.set(doc.text);
    }
  });
});
  

Я также убрал создание реактивного параметра var из автозапуска, потому что мы хотим создать его только один раз, а затем установить или получить его значение.

В качестве альтернативы, я упоминал ранее, что помощники автоматически запускаются. Это означает, что вы можете найти твит в помощнике, чтобы немного упростить свой шаблон:

 Template.tweet.helpers({
  text() {
    var doc = Tweets.findOne();
    if (doc) return doc.text;
  },
});
  

Что еще лучше, нам ReactiveVar больше не нужна и мы можем удалить всю onCreated функцию!