简体   繁体   中英

Meteor.js: How to periodically query collection documents from view

I have a view that I want to be essentially a dynamic slideshow:

  1. load a view
  2. start a timer so that every X seconds a random document from a particular collection is returned (typical collection.findOne() request)
  3. when that item is loaded, trigger a function with the data attached

this sounds like it could be a typical jquery _GET request, but it would be good to know the 'meteor' way of doing it.

Here is essentially a starting point of what I'd like to do:

// week_player.js


var randomWeekInterval;

// triggered when page is first loaded
Template.weekPlayer.rendered = function(){
    console.log('rendered!');
    var tick = 0;
    randomWeekInterval = Meteor.setInterval(function(){

        console.log('week interval update ' + (tick++));

        var weekCount = Weeks.find().count();
        var randomWeekId = Math.floor(weekCount * Math.random());

        var randomWeek = Weeks.findOne(randomWeekId);

        // TODO: add some sort of listener for when the week is loaded
        // and trigger newDataHandler with the data

    }, 10 * 1000); // repeat every 10 seconds
}

// triggered when the new data is loaded
Template.weekPlayer.newDataHandler = function(data){
    // got new data! here it is:
    console.log(data);
}

// triggered when leaving page: stop doing the interval
Template.postPage.destroyed = function(){
    Meteor.clearInterval(randomWeekInterval);
}

Try something like this:

_.extend(Template.weekPlayer, {
  created: function() {
    this.randomWeekInterval = Meteor.setInterval(function() {
      Session.set("randomWeekIndex", Math.floor(Weeks.find().count() * Math.random()));
    }, 10 * 1000);
  },

  destroyed: function() {
    Meteor.clearInterval(this.randomWeekInterval);
  },

  week: function() {
    return Weeks.findOne({}, {
      skip: Session.get("randomWeekIndex"),
      transform: function(doc) {
        // Here's where you can manipulate the object after it is retrieved

        return doc;
      }
    });
  }
});

Now you can get the week object directly from your template and it will automatically change to the new week whenever the Session var is changed:

<template name="weekPlayer">
  {{#with week}}
    Start Date: {{startDate}} <br/>
    End Date: {{endDate}}
  {{/with}}
</template>

A few notes:

  • The interval is set in the created callback, rather than the rendered . This is to ensure that there will always be only one setInterval for each clearInterval . If it's in the rendered callback a new interval will be set every single time the template is rendered, which could be hundreds of times. You also lose your references to your interval objects.

  • Because we reference the interval on this inside the created and destroyed callbacks, you can have multiple slideshows, each with their own interval objects.

  • We use Session to store the random index. The template helper function Template.weekPlayer.week will automatically be re-run every time that Session.set("randomWeekIndex", "someValue") is run. Then, the template will be automatically re-rendered because it depends on the week helper.

  • The HTML portion assumes that your week objects have startDate and endDate fields. They could of course follow any structure, and the transform option allows you to modify their structure however you need to before displaying them. If the objects are fine as they are, you can remove the transform option from the findOne call.

  • I'm using Underscore's _.extend for conciseness. If you haven't seen this before, it's the same as saying:

     Template.weekPlayer.created = function() { /* ... */ }; Template.weekPlayer.destroyed = function() { /* ... */ }; // ... 

A final note - you should find yourself very rarely using jQuery when using Meteor. Whenever you need to talk to the Meteor server you want to use Meteor methods instead of jQuery AJAX. Whenever you need to get data from the server you'll want to use publications/subscriptions. Whenever you want to do basic DOM manipulation, you'll let templates and reactive helper functions (eg Template.weekPlayer.week ) do it for you as I've shown here.

Session variables are reactive. You could use a template helper on the weekPlayer template that returns the Session object

Template Helper

Template.weekPlayer.helpers({
    currentSlide: function(){
        return Session.get('currentSlide');
    }
});

Template

<template name="weekPlayer">
    {{currentSlide}}
</template>

Periodic Updates

var tick = 0;
Meteor.setInterval(function() {
    // update contents of slide data
    tick += 1;
    // set currentSlide Session object -- which triggers a redraw
    Session.set('currentSlide', tick);
}, 1000);

Now a note on this, you might want to take the Meteor.setInterval call and move it outside of the Template.weekPlayer.rendered function. That way you're not creating a new Meteor.setInterval every time your redraw (or using Meteor.clearInterval -- just some mechanism to keep from call Session.set unexpectedly)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM