Search code examples
eventsmeteorpackageresumablejs

Can't get meteor FileCollection package to work


I am (unfortunately) working on a Windows machine so I had to manually add the FileCollection package to my app, but when I run my app, I can access the file collection and file collection methods from the browser console. However, I can't seem to get the event listeners set up on an actual page. (FYI, I am using iron-router for my templating architecture.)

It seems like the code that needs to be called is just not coming in the right order, but I've experimented with where I place the code and nothing seems to make a difference.

The server side code:

// Create a file collection, and enable file upload and download using HTTP
Images = new fileCollection('images',
  { resumable: true,   // Enable built-in resumable.js upload support
    http: [
      { method: 'get',
        path: '/:_id',  // this will be at route "/gridfs/images/:_id"
        lookup: function (params, query) {  // uses express style url params
          return { _id: params._id };       // a mongo query mapping url to myFiles
        }
      }
    ]
  }
);

if (Meteor.isServer) {

  // Only publish files owned by this userId, and ignore
  // file chunks being used by Resumable.js for current uploads
  Meteor.publish('myImages',
    function () {
      return Images.find({ 'metadata._Resumable': { $exists: false },
                   'metadata.owner': this.userId });
    }
  );

  // Allow rules for security. Should look familiar!
  // Without these, no file writes would be allowed
  Images.allow({
    remove: function (userId, file) {
      // Only owners can delete
      if (userId !== file.metadata.owner) {
        return false;
      } else {
        return true;
      }
    },
    // Client file document updates are all denied, implement Methods for that
    // This rule secures the HTTP REST interfaces' PUT/POST
    update: function (userId, file, fields) {
      // Only owners can upload file data
      if (userId !== file.metadata.owner) {
      return false;
      } else {
        return true;
      }
    },
    insert: function (userId, file) {
      // Assign the proper owner when a file is created
      file.metadata = file.metadata || {};
      file.metadata.owner = userId;
      return true;
    }
  });
}

The client side code (currently in main.js at the top level of the client dir):

if (Meteor.isClient) {
    // This assigns a file upload drop zone to some DOM node
Images.resumable.assignDrop($(".fileDrop"));

// This assigns a browse action to a DOM node
Images.resumable.assignBrowse($(".fileBrowse"));

// When a file is added via drag and drop
Images.resumable.on('fileAdded', function(file) {
// Create a new file in the file collection to upload
    Images.insert({
  _id : file.uniqueIdentifier, // This is the ID resumable will use
      filename : file.fileName,
      contentType : file.file.type
      }, function(err, _id) {// Callback to .insert
        if (err) {throwError('Image upload failed');}
    // Once the file exists on the server, start uploading
        Images.resumable.upload();
});
  });
  Images.resumable.on('fileSuccess', function(file) {
var userId = Meteor.userId();
var url = '/gridfs/images/' + file._id;
Meteor.users.update(userId, {
  $set : {
    "profile.$.imageURL" : url
  }
    });
Session.set('uploading', false);
  });
  Images.resumable.on('fileProgress', function(file) {
Session.set('uploading', true);
  });
}

Solution

  • I think the issue might be with using IronRouter. I'll assume you are using some layout.html via Iron router and inside it you've added your template for your file table to be shown. (I'm guessing your are following the sampleApp that came with fileCollection.). I had a problem when I did this and it had to do with where I had the code that attached the listeners. The problem is where you have the code "Images.resumable.assignDrop($(".fileDrop"));" in your client file. The way you have it now, that line of code is running before your template is rendered within the layout.html. So the code can not find the DOM element ".fileDrop". To fix this create a layout.js file and use the rendered method like this...

    Template.layout.rendered = function(){
        Images.resumable.assignDrop($(".fileDrop"));
    }