Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Backbone Marionette: Don't display view before all images have loaded

Im displaying a CompositeView, in which each model has a property which is an url for an image. If I just .show the view in a region the images have not finished loading, which doesnt look very sexy (they are displayed when they have loaded).

I would like to wait until all images have loaded, before I display the view. Right now, Im trying to make it work by deferring image loads, but this is probably not the right way (perhaps this 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"
  });

});
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);
        });

      });

    }

  };

});
like image 711
tolborg Avatar asked Jan 21 '26 04:01

tolborg


1 Answers

I think your approach is correct, I will try to encapsulate the data/image loading in 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 you controller, as you already have it, when the repository finish the loading the controller just render the data on the view, something similar to server side MVC with repositories,

getAll() will contain the code that you have now on the controller to load the data and images, the repository will be an extra module on your marionette application.

So your method getAll will 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 loads, I will probably use a counter set at the total number of images(from the collection), and decrement it each time a load handler is executed. $(window).load() could be and option this will fire after the entire page is loaded.

Thanks.

like image 149
Arturo Soto Avatar answered Jan 23 '26 19:01

Arturo Soto



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!