Question

When using the Isotope plugin in Meteor, Isotope always apply a style of height: 0 to the Isotope div .grid-container. This can be due to the plugin initializing before the images have loaded. Running $('.grid-container').isotope() in the console manually causes Isotope to make the div visible.

Question: How can we trigger the plugin initialization only after all the images in div .item have loaded? Calling Isotope's imagesLoaded method from within Template.name.rendered does not seem to work.

main.js

Template.main.rendered = function () {

     $('.grid-container').imagesLoaded(function() {
        $('.grid-container').isotope({
            itemSelector: '.item',
            layoutMode: 'masonry',
            masonry: {
                columnWidth: 200
            }
        })
     })

};

main.html

<template name="main">
    <div class="grid-container">

        {{#each items}}
            {{> item}}
        {{/each}}

    </div>
</template>
Was it helpful?

Solution

As requested in the comment above...

Here's how to use an intermediate DOM element for isotope image loading before doing a final append and layout.

This example is for Backbone but should work fine in Meteor. The crucial aspect in both cases is initializing isotope() on an empty element. For example: <div class="isotope"></div>

As you can see below, I have a grid_view in Backbone that handles all of this and renders items one at a time as they are added to the collection. Naturally, in Meteor that's not the approach to take.

For the record, I'm not sure if the Meteor example would work out of the box but it's not far off. I haven't used isotope in Meteor as I mentioned. The Backbone example is solid and works in production for us.

Here are the examples...

Meteor Example:

// In Meteor, you want your collection and the DOM element
Template.main.rendered = function() {

  // Pretty sure this.$ selector works in Meteor rendered
  this.$container = this.$('.isotope').isotope({
    itemSelector: '.gridItem',
    masonry: {
      columnWidth: '.gridSizer',
      gutter: '.gutterSizer'
    }
  });

  var items = CollectionName.find().fetch();

  var $holder = $('<div></div>')

  _.each(items, function(item) {
    // However you load external or partial templates in Meteor (not sure)
    $holder.append(partialTemplate(item));        
  }

  // Load images
  $holder.imagesLoaded(function() {
    // Append and layout on isotope        
    self.$container.append(item).isotope('appended', $holder);
  });
}

In Meteor, you could use the added callback in your publish function, to send the models to the client one at a time if you wanted. I haven't dug into pagination with Meteor to know the best way to handle that.

Backbone Example:

// Collection Add event
renderItem: function(model) {
  var self = this;

  // Run it through template
  var item = $(self._template(model.toJSON()));

  // Load images
  item.imagesLoaded(function() {
    // Append and layout on isotope        
    self.$container.append(item).isotope('appended', item);
  });
}

// Standard view render function
render: function() {
   this.$container = this.$el.isotope({
    itemSelector: '.gridItem',
    masonry: {
      columnWidth: '.gridSizer',
      gutter: '.gutterSizer'
    }
  });
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top