简体   繁体   English

MeteorJS:依次加载…模板

[英]MeteorJS: Loading… templates sequentially

So, essentially, I have a collection with multiple categories of photos. 因此,基本上,我有一个包含多种类别照片的收藏集。 I currently have this setup for going through the categories and loading a template for each one: 我目前使用此设置来浏览类别并为每个类别加载模板:

{{#each categories}}
  {{>gallery collectionName=categoryName}}
{{/each}}

So, this is great for dynamically building each section using the gallery template. 因此,这对于使用Gallery模板动态构建每个部分非常有用。

As each gallery has it's own collection of images, I have added a helper function inside the gallery template to call on the respective collection and then for each collection image, add it to the gallery. 由于每个画廊都有自己的图像集合,因此我在画廊模板内添加了一个辅助函数来调用相应的集合,然后针对每个集合图像将其添加到画廊中。

(inside the gallery template) (在图库模板内)

{{loadPhotos collectionName}}

Now, you can probably see the problem. 现在,您可能可以看到问题了。

The gallery divs are created first, empty, then all at once, all the photos are added to all the divs. 首先创建图库div,将其创建为空,然后一次全部创建,然后将所有照片添加到所有div中。

I would prefer, each gallery shows a loading circle until the photos are all added, then the next gallery starts loading the photos and the loading circle disappears when all it's photos are loaded. 我希望每个画廊都显示一个加载圈,直到所有照片都添加完毕,然后下一个画廊开始加载照片,并且加载所有照片时,加载圈消失。 This continues until all the categories have been loaded. 这将继续,直到所有类别都已加载。

I am using jquery to add the photos and FlowRouter if that helps... 我正在使用jQuery添加照片和FlowRouter,如果有帮助...

Thanks for your time and any solutions offered! 感谢您的时间和提供的任何解决方案!

I have had to do similar types of things in the past and the way that I have been able to do it is by creating a way to communicate between templates and sub-templates. 过去,我不得不做类似的事情,而我能够做的是通过创建一种在模板和子模板之间进行通信的方式。 The primary ways to do this is by passing a callback function to each child template or by passing a ReactiveVar , ReactiveDict , or any other reactive computation that the parent is "listening" to. 完成此操作的主要方法是将回调函数传递给每个子模板,或者传递ReactiveVarReactiveDict或父级“监听”的任何其他反应式计算。 I tested the below approach and it should work perfectly for what you are after. 我测试了以下方法,它应该完全适合您的需求。

First the main categories template. 首先是主要类别模板。

<template name="photoGallery">
  {{#each cat in categories}}
    {{> gallery collectionName=cat.name loadNow=loadTrigger isLoaded=loadedIndicator}}
  {{/each}}
</template>

And the associated Javascript. 以及相关的Javascript。 Note, for this example I am subscribing to a publication called photoCategories which publishes a set of documents from a collection called Categories (which contains a list of gallery categories in the name property and the order I want them loaded in the loadOrder property). 请注意,在此示例中,我正在订阅一个名为photoCategories的出版物,该出版物从名为Categories的集合中发布了一组文档(该集合在name属性中包含画廊类别的列表,并希望它们在loadOrder属性中加载的loadOrder )。 Your specifics are likely different. 您的具体情况可能有所不同。

import { Template } from 'meteor/templating';
import { Categories } from '../../../api/categories/categories.js';
import { ReactiveDict } from 'meteor/reactive-dict';
import { ReactiveVar } from 'meteor/reactive-var';

import './photoGallery.html';
import '../utils/loading-indicator.html';

Template.photoGallery.onCreated(function() {
  this.loadTrigger = new ReactiveDict('loadTrigger');
  this.lastLoaded = new ReactiveVar();
  this.loadOrder = [];

  // subscribe to category data and when complete build loading controls
  // in this example the collection that contains the categories is called
  // 'Categories' and each document contains a property called 'loadOrder'
  // to control the order to load the galleries
  this.subscribe('photoCategories', () => {
    // we are inside the 'onComplete' subscription callback
    Categories.find({}, {sort: {loadOrder: 1}}).forEach((category) => {
      // create a trigger for each gallery so we can communicate when to load
      // initialize each trigger to false for now
      this.loadTrigger.set(category.name, false);

      // we need to also keep track of our load order so we know which
      // gallery to trigger next
      this.loadOrder.push(category.name);
    });

    // now that everything is initialized, lets trigger the first gallery to load
    this.loadTrigger.set(this.loadOrder[0], true);
  });

  // re-runs everytime a gallery is finished loading
  this.autorun(() => {
    // get which gallery just finished loading
    var lastLoaded = this.lastLoaded.get();
    var lastLoadedIndex = this.loadOrder.indexOf(lastLoaded);

    // make sure we have more galleries to load
    if (lastLoadedIndex + 1 < this.loadOrder.length) {
      // get the next gallery to load
      var loadNext = this.loadOrder[lastLoadedIndex + 1];

      // trigger the gallery to load
      Tracker.afterFlush(() => {
        this.loadTrigger.set(loadNext, true);
      });
    }
  });
});

Template.photoGallery.helpers({
  // returns our photo gallery categories to iterate over in our template
  categories: function() {
    return Categories.find({}, {sort: {loadOrder: 1}});
  },

  // returns our ReactiveDict so we can communicate to our sub-template
  // galleries when they can load
  loadTrigger: function() {
    return Template.instance().loadTrigger;
  },

  // returns our ReactiveVar used to keep track of which gallery just loaded
  loadedIndicator: function() {
    return Template.instance().lastLoaded;
  },
});

Basically, what we are doing here is subscribing to the publication that contains the list of categories. 基本上,我们在这里所做的是订阅包含类别列表的出版物。 Then we build a dictionary of load triggers that we will use to trigger each gallery to load. 然后,我们建立一个加载触发器字典,用它来触发每个画廊的加载。 We also need to define a last loaded trigger so we know when the gallery is done loading (and can trigger the next one to load). 我们还需要定义一个最后加载的触发器,以便我们知道画廊何时加载(并可以触发下一个加载)。

To make sure this all works correctly, we need to make sure the load triggers and last loaded trigger are passed to the gallery templates (so they can be triggered to load and indicate back once they are done). 为了确保所有操作均正常进行,我们需要确保将加载触发器和最后加载的触发器传递给图库模板(以便可以触发它们加载并在完成后指示返回)。

Now let's look at the gallery template. 现在,让我们看一下图库模板。

<template name="gallery">
  {{#if okToLoadNow collectionName}}
    {{loadPhotos collectionName}}
  {{else}}
    {{> loading_indicator }}
  {{/if}}
</template>

And associated javascript. 以及相关的javascript。

Template.gallery.helpers({
  // reactive checks if we are ok to load
  okToLoadNow: function(collectionName) {
    return Template.instance().data.loadNow.get(collectionName);
  },

  // contains logic that loads photos, renders them on the page, then triggers
  // back once the loading is complete
  loadPhotos: function(collectionName) {
    const instance = Template.instance();

    // insert the code that loads the photos and renders them on the page here!
    // if the logic is complete it probably makes more sense to put this in a sub-template
    // and put the logic in the `onRendered` callback

    // lets simulate loading by pausing for 3 seconds then communicate back
    // that we loaded
    Meteor.setTimeout(() => {
      instance.data.isLoaded.set(collectionName);
    }, 3000);
  },
});

In the gallery template, we show a loading indicator until we are triggered to load. 在图库模板中,我们将显示一个加载指示器,直到触发加载。 Once we are finished loading, we then indicate (via the isLoaded trigger) that we are done. 加载完成后,然后(通过isLoaded触发器)指示已完成。 For this we just pass back the gallery name that just loaded. 为此,我们只需传回刚刚加载的图库名称。

As I mentioned earlier, I was able to test that this approach works. 如前所述,我能够测试这种方法是否有效。 You should just be able to adapt it with your specifics. 您应该只能够根据自己的具体情况进行调整。

Let me know how it goes! 让我知道事情的后续!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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