Meteor: Tracker.autorun / observeChanges & collections not working as expected

守給你的承諾、 提交于 2019-12-19 10:10:10

问题


I am new to using meteor, so I am hoping to receive a very basic explanation of how these functions work, and how I am supposed to be using them. Otherwise, if there is a method that would be better suited to what I am hoping to achieve, the knowledge would be appreciated.

The functionality I was hoping to achieve:

I have a Mongo collection that contains a number value within documents that are assigned to specific users.

I will use the value that I get from the document to populate a width: xx% in some css in-line styling on a 'progressbar'. But the other use I have for it is performing some kind of 'reactive' function that runs whenever this value changes which can update the background color of this progress bar dynamically based off of the current value of the progressbar. Think 'red' for low and 'green' for high:

project.html:

<template name="progressBar">
  <div id="progress-bar" style="width:{{curValue}}; background-color:*dynamicColor*;"></div>
</template>

project.js:

Progress = new Mongo.Collection("progress");

Template.progressBar.helpers({
  curValue: function () {
    return Progress.findOne({user: Meteor.userId()}).curValue;
  }
});

The above sometimes works. But it doesn't seem to be reliable and isn't working for me right now. I get errors about cannot read property 'curValue' of undefined. From what I have researched online, that means that I am trying to access this document before the collection has loaded. But I really cannot find a direct solution or wrap my head around how I am supposed to be structuring this to avoid that error.

The next problem is observing changes to that value and running a function to change the background color if it does change.

Here are a few of the types of autorun/observe pieces of code I have tried to make work:

Session.set('currentValue', Progress.findOne({user:Meteor.userId()}).curValue);
Tracker.autorun(function(){
  var currentValue = Session.get('currentValue');
  updateColor(currentValue);
});

var currentValue = Progress.findOne({user:Meteor.userId()}).curValue);
var handle = currentValue.observeChanges({
  changed: function (id, currentValue) {
    updateColor(currentValue);
  }
});

To sum up the question/problem:

I want to use a value from a mongo db document in some in-line css, and also track changes on that value. When the value changes, I want a function to run that will update the background color of a div.


Update

Using @Ethaan 's answer below, I was able to correct my subscription/template usage of my collection data. I did a bit more digging and come to a greater understanding of the publish/subscribe methods and learned how to properly use the callbacks on subscriptions to run my Tracker.autorun function at the appropriate time after my collection had loaded. I was able to expand on the answer given to me below to include a reactive Tracker.autorun that will run a function for me to update my color based on my document value.

The code that I ultimately got working is as follows:

project.js

if (Meteor.isClient) {

  Progress = new Mongo.Collection("progress");

  Template.content.onCreated(function () {
    var self = this;

    self.autorun(function () {
      self.subscribe("progress", function(){
        Tracker.autorun(function(){
          var query = Progress.findOne({user: Meteor.userId()}).level;
          changeColor(query);
        });
      });
    });
  });

  Template.content.helpers({
    value: function(){
      return Progress.findOne({user: Meteor.userId()}).level;
    }
  });

  function changeColor(value){
    //run some code
  }

}

if (Meteor.isServer) {

  Progress = new Mongo.Collection("progress");

  Meteor.publish("progress", function () {
    return Progress.find({user: this.userId});
  });

}

project.html

<head>
  <title>Project</title>
</head>

<body>
  {{> standard}}
</body>

<template name="standard">
  ...
  {{> content}}
</template>

<template name="content">
  {{#if Template.subscriptionsReady}}
      {{value}}
    {{else}}
       0
   {{/if}}
</template>

回答1:


that means that I am trying to access this document before the collection has loaded

Seems like you get the problem, now lets get ride to some possible solutions.

Meteor version 1.1

If you are using the new meteor version 1.1 (you can check running meteor --version)

use this.

First on the onCreated function use this.

Template.progressBar.onCreated(function () {
  var self = this;

  self.autorun(function () {
    self.subscribe("Progress");
  });
});

See more about subscriptionReady on the DOCS. Now on the HTML use like this.

<template name="progress">
  {{#if Template.subscriptionsReady}}
      <div id="progress-bar" style="width:{{curValue}}; background-color:*dynamicColor*;"></div>
    {{else}}
       {{> spinner}} <!-- or whatever you have to put on the loading -->
   {{/if}}
</template>

Meteor under 1.0.4

You can have on the router something like a waitOn:function(){}

waitOn:function(){
  Meteor.subscribe("Progress");
}

or since helper are asynchronous do something like this (not recommendable).

Template.progressBar.helpers({
  curValue: function () {
    query = Progress.findOne({user: Meteor.userId()}).curValue;
    if(query != undefined){
      return query;
    }else{
     console.log("collection isn't ready")
    }
  }
});


来源:https://stackoverflow.com/questions/29443513/meteor-tracker-autorun-observechanges-collections-not-working-as-expected

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!