Magic grid: Don't show view before loading all images

Im displaying a CompositeView in which each model has a property that is the url for the image. If I just show the view in the area, the images haven't finished loading, which doesn't look very sexy (they are displayed when they are loaded).

I would like to wait for all the images to be loaded before I render the view. Right now, I'm trying to get it to work by postponing the load on the image, but this is probably not the most correct way (maybe it should be done on the model?).

applications/list_view.js

      

App.module("ApplicationsApp.List", function(List, App, Backbone, Marionette, $, _){

  List.Application = Marionette.ItemView.extend({
    tagName: 'li',
    template: Templates.applications.application
  });

  List.Applications = Marionette.CompositeView.extend({
    className: "applications",
    template: Templates.applications.applications,
    childView: List.Application,
    childViewContainer: "ul"
  });

});
      

Run codeHide result


applications/list_controller.js

      

App.module("ApplicationsApp.List", function(List, App, Backbone, Marionette, $, _) {

  List.Controller = {

    listApplications: function() {
      // Set layout
      App.trigger("set:layout:authenticated");

      // Fetch the applications
      var fetchingApplications = App.request('application:entities');

      $.when(fetchingApplications).done(function(applications) {

        var applicationsListView = new List.Applications({
          collection: applications
        });


        var deferreds = [];

        applications.each(function(application) {

          deferreds.push(function() {
            var loader = new Image();
            loader.onload = function() {
              console.log(application.get("image_path"));
            };
            loader.src = application.get("image_path");
          });

        });

        $.when.apply($, deferreds).then(function() {
          App.layout.mainRegion.show(applicationsListView);
        });

      });

    }

  };

});
      

Run codeHide result


+3


source to share


2 answers


I think your approach is correct, I will try to encapsulate the data / image loading into one function using a repository, probably

    $.when(applicationsRepository.getAll()).then(function (apps) {
        var appsView = new App.Views.ApplicationListView({ collection: apps});
        App.layout.mainRegion.show(appsView );
    });

      

So this code will be part of your controller, as you already know it, when the repository finishes downloading, the controller just displays the data on the screen, something similar to server side MVC with repositories.

getAll () will contain the code you have on the controller to load data and images, the repository will be an additional module in your puppet app.



So your getAll method would be something like

    var getAll = function () {
        var deferred = $.Deferred();
        _getAll(function (apps) {
            deferred.resolve(apps);
        });
        return deferred.promise();
    };

    var _getAll = function (callback) {
        //code to create the app collection
        apps.on("reset", function(apps){
            //load images
            //callback(apps);
        });
        apps.fetch({ reset: true });
    };

      

To identify and perform some action (callback) after the last image is loaded, I will probably use a counter set on the total number of images (from the collection) and decrement it every time the load handler is executed. $ (window) .load () may be and the option will fire after the entire page has loaded.

Thank.

+1


source


I ended up doing this (inspired by Wait for the image to load before proceeding ):

applications/list_controller.js

      



App.module("ApplicationsApp.List", function(List, App, Backbone, Marionette, $, _) {

  List.Controller = {

    listApplications: function() {
      self = this;
      // Set layout
      App.trigger("set:layout:authenticated");

      // Fetch the applications
      var fetchingApplications = App.request('application:entities');

      // Perform actions when applications have been fetched
      $.when(fetchingApplications).done(function(applications) {

        // Load all images in applications
        var imgLoaders = [];

        applications.each(function(application) {
          var src = application.get("image_path");
          imgLoaders.push(self.loadImage(src));
        });

        // Perform actions when images have been loaded
        $.when.apply($, imgLoaders).done(function() {
          var applicationsListView = new List.Applications({
            collection: applications
          });
          App.layout.mainRegion.show(applicationsListView);
        });

      });

    },

    loadImage: function(src) {
      var deferred = $.Deferred();
      var img = new Image();
      img.onload = function() {
        deferred.resolve();
      };
      img.src = src;
      return deferred.promise();
    }

  };

});
      

Run codeHide result


0


source







All Articles