Hi, I’m still trying to figure out Meteor-Files.
What I’m trying to achieve: I have a collection named “Characters” and a FilesCollection named “Images”.
Every document in “Characters” is supposed to have one image assigned to them. It would basically work like profile pictures where every user can upload his image.
Due to my previous experiences in PHP I did something like that with linking two tables in MySQL to achieve that. But I’m clueless on how to do that with Mongo/Meteor-Files.
Here is what I have so far: The file-upload-system is a very slightly modified version of what is shown on Meteor-Files-Github.
imports/api/images/images.js
// Definition of the image collection
import { Meteor } from 'meteor/meteor';
import { FilesCollection } from 'meteor/ostrio:files';
export const Images = new FilesCollection({
collectionName: 'Images',
allowClientCode: false, // Disallow remove files from Client
onBeforeUpload(file) {
// Allow upload files under 10MB, and only in png/jpg/jpeg formats
if (file.size <= 10485760 && /png|jpg|jpeg/i.test(file.extension)) {
return true;
}
return 'Please upload image, with size equal or less than 10MB';
}
});
if (Meteor.isClient) {
Meteor.subscribe('files.images.all');
}
if (Meteor.isServer) {
// Upload sample files on server's startup:
Meteor.startup(() => {
Images.load('https://raw.githubusercontent.com/VeliovGroup/Meteor-Files/master/logo.png', {
fileName: 'logo.png'
});
});
} else {
// Subscribe to file's collections on Client
Meteor.subscribe('files.images.all');
}
imports/api/images/methods.js
//Empty yet, but I figure I'll need methods in order
//to link these two collections
imports/api/images/server/publications.js
import { Images } from '../images.js';
Meteor.publish('files.images.all', function () {
return Images.find().cursor;
});
ui/components/upload_image.html
The Templates I use for uploading:
<template name="uploadForm">
{{#with currentUpload}}
Uploading <b>{{file.name}}</b>
<span id="progress">{{progress.get}}%</span>
{{else}}
<input id="fileInput" type="file" />
{{/with}}
</template>
<template name='file'>
<img src="{{imageFile.link}}" alt="{{imageFile.name}}" width="360px" height="450px" />
<!-- Same as: -->
<!-- <img src="{{fileURL imageFile}}" alt="{{imageFile.name}}" /> -->
</template>
ui/components/upload_image.js
And the js-File for the templates
import { Images } from '/imports/api/images/images.js'
import { Template } from 'meteor/templating';
import { ReactiveVar } from 'meteor/reactive-var';
Template.uploadForm.onCreated(function () {
this.currentUpload = new ReactiveVar(false);
});
Template.uploadForm.helpers({
currentUpload() {
return Template.instance().currentUpload.get();
}
});
Template.uploadForm.events({
'change #fileInput'(e, template) {
if (e.currentTarget.files && e.currentTarget.files[0]) {
// We upload only one file, in case
// multiple files were selected
const upload = Images.insert({
file: e.currentTarget.files[0],
streams: 'dynamic',
chunkSize: 'dynamic'
}, false);
upload.on('start', function () {
template.currentUpload.set(this);
});
upload.on('end', function (error, fileObj) {
if (error) {
alert('Error during upload: ' + error);
} else {
alert('File "' + fileObj.name + '" successfully uploaded');
}
template.currentUpload.set(false);
});
upload.start();
}
}
});
Template.file.helpers({
imageFile() {
return Images.findOne();
},
});
My character collection set up looks as follows:
imports/api/characters/characters.js
// Definition of the news collection
import { Mongo } from 'meteor/mongo';
export const Characters = new Mongo.Collection('characters');
imports/api/characters/methods.js
// Methods related to news
import { Meteor } from 'meteor/meteor';
import { check } from 'meteor/check';
import { Characters } from './characters.js';
////////////////
Meteor.methods({
'characters.start'(name) {
check(name, String);
// Make sure the user is logged in before creating character
if (! Meteor.userId()) {throw new Meteor.Error('not-authorized');}
return Characters.insert({
name,
species: "",
gender: "",
age: "",
occu: "",
weight: "",
height: "",
statue: "",
skincolor: "",
haircolor: "",
hair: "",
eyecolor: "",
chardesc: "",
room: "",
createdAt: new Date(),
owner: Meteor.user().username,
});
},
'characters.remove'(charactersId) {
check(charactersId, String);
Characters.remove(charactersId);
},
'characters.update'(name, species, gender, age, occu, weight, height, statue, skincolor, haircolor, hair, eyecolor, chardesc) {
//check(charactersId, String);
check(name, String);
check(species, String);
check(gender, String);
check(age, String);
check(occu, String);
check(weight, String);
check(height, String);
check(statue, String);
check(skincolor, String);
check(haircolor, String);
check(hair, String);
check(eyecolor, String);
check(chardesc, String);
// user has to be logged in before updating content
if (! Meteor.userId()) {throw new Meteor.Error('not-authorized');}
Characters.update({name: name}, { //The parentheses was closed before the $set in your code
$set: {
name:name,
species:species,
gender:gender,
age:age,
occu:occu,
weight:weight,
height:height,
statue:statue,
skincolor:skincolor,
haircolor:haircolor,
hair:hair,
eyecolor:eyecolor,
chardesc:chardesc
},
});
},
'charactersRoom.update'(name, room) {
check(room, String)
check(name, String)
if (! Meteor.userId()) {throw new Meteor.Error('not-authorized');}
Characters.update({name: name}, {
$set: {
name:name,
room: room,
},
});
},
});
imports/api/characters/server/publications.js
// Own Characters
Meteor.publish('characters.all', function () {
if (this.userId) {
return Characters.find({owner: Meteor.user().username});
}
});
My question is, where to start. Even a push in the right direction would be appreciated since I’m so clueless that I don’t know what exactly I have to learn. My initial idea was to somehow use the Meteor.method ‘characters.start’ in order to somehow put the image adress value of the FilesCollection in a new image-key of the characters-collection.
Edit: Uploading and streaming images work already.