Метеор: «Ошибка типа: undefined не является объектом» при использовании коллекции - PullRequest
1 голос
/ 06 марта 2019

Я просто пробую Метеор и вообще не очень продвинут в Javascript.Я пытаюсь отобразить свойство text объекта из коллекции на стороне клиента с помощью шаблона, но я получаю сообщение об ошибке, указанное в заголовке.Я немного изменил базовый проект 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 здесь или эта ошибка как-то связана с тем, как работает Метеор?

1 Ответ

2 голосов
/ 06 марта 2019

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

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

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

В вашем случае это означает, что при запуске 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);
    }
  });
});

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

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

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

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

...