0
votes

I have a view with multiple collections, implemented like this:

collection: {
   folders: new FolderCollection(),
   images: new ImageCollection(),
   files: new FileCollection()
},

And example collection is like this:

var FolderCollection = Backbone.Collection.extend({
    model: folderObj,
    initialize:function (){
        // this.bindAll(this);
        // this.setElement(this.at(0));
    },
    comparator: function(model) {
        return model.get("id");
    },
    getElement: function() {
        return this.currentElement;
    },
    setElement: function(model) {
        this.currentElement = model;
    },
    next: function (){
        this.setElement(this.at(this.indexOf(this.getElement()) + 1));
        return this;
    },
    prev: function() {
        this.setElement(this.at(this.indexOf(this.getElement()) - 1));
        return this;
    }
});

As you can imagine, this View is a display for files, images, and folders. I then populate the view by calling three different functions; one to populate the view with folders, another for files, and another for images. Each of these functions is a separate ajax request. So, because these calls are asynchronous, there's no way to first load folders, then images, then files and there is no consistency when the page loads.

So, my problem is, I need to be able to order these three collections in multiple ways. The first problem is, since the calls are async, sometimes the folders load first, or maybe the files, etc. I can think of two ways to fix this:

  1. Only call the next function after the previous is completed. Is this the best way? If so, how do I do that

  2. After all the collections are loaded, sort them. If so, how is the best way to sort and order multiple collections?

If more code is needed (ie: model or view) please let me know and I can provide what ever is needed.

thanks jason

EDIT - SHOWING VIEW

var FileManagementView = TemplateView.extend({
    viewName: 'fileManagement',
    className: 'fileManagement',
    events: {
            //my events

    },
    collection: {
        folders: new FolderCollection(),
        images: new ImageCollection(),
        files: new FileCollection()
    },
    //life cycle
    initialize: function (options) {
        TemplateView.prototype.initialize.apply(this, [options]);      

    },
    templateContext: function (renderOptions) {   
    },

    postRender: function () {
        //more functions to set up the view
        this.repopulateViewWithFoldersAndFiles(currentFolderId);
    },
    template: function (renderOptions) {
        return 'MyMainTemplate';
    },
    repopulateViewWithFoldersAndFiles: function(currentFolderId){
        //code to do stuff to create view

        //these functions are all async, so theres no way to know what will finish first
        this.getFolders(currentFolderId);
        this.getImages();
        this.getFiles();

    },
    getFiles: function(){
        try{
            var that = this;
            var url = '?q=url to function';

            $.ajax({
                url: url,
                context: that,
                data:{'methodName': 'getFiles'}
            }).done(function(data) {
                var results =  jQuery.parseJSON(data.result.results);
                if(results){
                    $.each(results, function( key, value ) {
                         var file = new fileObj;
                        file.set('id', value.id);
                        file.set('fileName', value.fileName);
                        //...set more attributes
                        that.collection.files.add(file);
                        that.renderFile(file);
                    });
                }
            });
        }  catch(e){
            throw e;
        }
    },

    renderFile: function(file){
        try{
            if(file) {
                var template = window.app.getTemplate('AnotherTemplate');
                var html = $(template({
                    id: file.get('id'),
                    fileName: file.get('fileName'),
                    fileIconPath: file.get('fileIconPath')

                }));
                this.$el.find('#fileDropZone').append(html);
            }
        }  catch(e){
            throw e;
        }
    },    
    getImages: function(){
        try{            
            var url = '?q=url to function';
            $.ajax({
                url: url,
                context: that,
                data:{'methodName': 'getImages'}
            }).done(function(data) {
                var results =  jQuery.parseJSON(data.result.results);
                if(results){
                    $.each(results, function( key, value ) {                        
                        var image = new imageObj;
                        image.set('id', value.id);
                        image.set('imgTitle', value.image_name);
                        //....set more attributes
                        that.collection.images.add(image);
                        that.renderImage(image);
                    });
                }
            });
        }  catch(e){
            throw e;
        }
    },
    renderImage: function(image){
        try{
            if(image) {
                var template = window.app.getTemplate('myViewTemplate');
                var html = $(template({
                    imgId: image.get('id'),
                    imgTitle: image.get('imgTitle'),
                    //..more attributes
                }));
                this.$el.find('#fileDropZone').append(html);
            }
        }  catch(e){
            throw e;
        }
    },       
    getFolders:function(parentId){
        var that = this;
        var url = '?q=...path to function';

        $.ajax({
            url: url,
            context: that,
            data:{'methodName': 'getFolders'}
        }).done(function(data) {
            var results =  jQuery.parseJSON(data.result.results);
            if(results){
                $.each(results, function( key, value ) {
                    var folder = new folderObj();
                    folder.set('folderName', value.folder_name);                    
                    folder.set('id', value.folder_id);
                    //more attributes
                    that.collection.folders.add(folder);
                    that.renderFolders(folder);
                });
            }else{
                this.renderFolders(null);
            }
        });
    },
    //renders the folders to the view
    renderFolders: function(folder){
        try{
            if(folder) {
                var template = window.app.getTemplate('myFolderTemplate');
                var html = $(template({
                    folderId: folder.get('id'),
                    folderName: folder.get('folderName'),                 
                }));
                this.$el.find('#fileDropZone').append(html);
            }
        }  catch(e){
            throw e;
        }
    }   
});
1
Did you try promises? - Lesha Ogonkov
Can you show your view also? - antejan
Lesha, I'm not sure what you mean by "Promises"? antejan, yes, I will add a stripped down version of my view. - jason
You defenitely need to look at Promises. Also, you choose a wrong way, when tired to make calls from View, View should respond to Model/Collection update. You better do your calls outside of your View. - Lesha Ogonkov

1 Answers

0
votes

What I ended up doing was rewriting my models and creating one model that the others inherit from. Example:

var DataModel =MyBaseModel.extend({
    defaults: {
        id: null,
        //other shared fields
    }
});

All my other models inherited, like this:

var folderObj = DataModel.extend({
    // Whatever you want in here
    urlRoot: '?q=myApp/api/myClassName/',
    defaults: {
        //other fields here

    },
    validate: function(attributes){
          //validation here
    }
});

I then used deferred, which I answered here: Jquery Promise and Defered with returned results