4

I'm trying to develop a simple file browser using Backbone for the client and Node.js for the server. At the moment I'm quite stuck on how to design the model when it comes to subfolder

Client code looks something like

app.MyFile = Backbone.Model.extend({
    defaults: {
        path: '', // id of the model will be the path + filename
        content: '', // content of the file
        isDir: false // if file is a directory
    }
});

var MyFileList = Backbone.Collection.extend({
  model: app.MyFile,
  url: '/api/files'
});

// create global collection of files
app.MyFiles = new MyFileList();

// displays file name
var MyFileItemView = Backbone.View.extend({
    events: {
      'click .clickable': 'view'
    },

    ...

    view: function (source) {
        if (this.model.toJSON().isDir) {
            this.model.fetch();
            // XXX what to do here

            _.each(this.model.get('content'), function (obj) {
               console.log(obj.toJSON()); // error - no toJSON method
            });

        } else {
            // calls another view that calls the model.fetch 
            // to display the content (no issue here)

        }
    },
});


var MyFilesListView = Backbone.View.extend({
    initialize: function () {
      // XXX Not sure if I should listen on MyFiles collection...
      app.MyFiles.on('reset', this.render, this);
    },

    render: function () {
      app.MyFiles.each(function (file) {
        new MyFileItemView({model:file});
      }, this);

});

app.AppView = Backbone.View.extend({
  initialize: function () {
    // fetch all files
    app.MyFileList.fetch();
  }
});

// app.js (point of entry)
$(function() {
  // Kick things off by creating the **App**.
  new app.AppView();
});

My server code:

var express = require("express"), 

...

app.get('/api/files', function(req, res) {
    ...
    // return file list (including folder - no issue here)
}

app.get('/api/files/:id', function(req, res) {
    var fileModel = createFileModel(req.params.id); // create file model

    if (!fileModel.isDir) {
        // if file is not directory, then simply read the content and return
        // it back to the client -- no issue
        ...
    } else {
        var files = [];
        // read the directory to find all the files and push it to 
        // files array
        ...

        fileModel.content = files;
        res.send(fileModel);
    }
}

At the moment I'm not sure what is the correct way to do this. My questions:

  1. How to represent the model object itself. Should I just set the content to collection of MyFile if isDir===true? If this is the case, how should I do that? calling toJSON() on the model's content throws an exception because toJSON is not defined
  2. Also on the MyFilesListView should it listen to the global collection as well? Now that I need to handle sub folders it doesn't seem right.
  3. Or should I overrides the global collection when trying to view the subfolder?
  4. Is my server code implementation correct? The problem I'm having now is that when I put the content into array and send fileModel back to the client, the list of files are not reflected in the model itself - perhaps I must override parse?

I read some posts here

But I'm still not sure how to apply it... Javascript is confusing :(

Community
  • 1
  • 1
GantengX
  • 1,471
  • 2
  • 16
  • 28

1 Answers1

1

You can write a simple model within a model with a simple function like this in your single model ( xfile model you can call it! ) :

  loadFolders : function() {
    if (this.get('isDir')) {
      var self = this;
      self.subFolders = [];
      _.each(self.get('files'), function(data) {
        file = new File(data);
        self.subFolders.push(file);
      });
    }
  }

and do the same in your view model to render correct tree view.

And in your express.js backend ( I'm not familiar with that framework ) you just send proper json to your backbone models.

If your data is too long and you want to get each model directory seperately ( when user expand folder in your view ) you can create a model with lots of collections ( or collection with lots of collection ) with the same idea, then fetch data from server in the model, and the backend must support directories, something like this : /api/file/folder1/folder2/file1.txt

Another way to do something more magical is using a relational model ( by any backbone extension that provide such feature )

If you want to read more about :

A marionette.js example that do the same

Backbone.Relational - a relational extension for bakcbone

PS : I can't provide more links, so you can search for Backbone.associate, that's another relational extension for backbone

PS 2 : You can use coffeescript, its making javascript syntax simpler and more readable.

KiT O
  • 867
  • 6
  • 21