I want users to upload photos for their profile and I want to display their photo on the navbar when they're logged in.
These are the instructions for the lepozepo:cloudinary package (I am open to other alternatives):
Step 1
SERVER
Cloudinary.config
cloud_name: 'cloud_name'
api_key: '1237419'
api_secret: 'asdf24adsfjk'
CLIENT
$.cloudinary.config
cloud_name:"cloud_name"
Step 2
Wire up your input[type="file"]. CLIENT SIDE.
Template.yourtemplate.events
"change input[type='file']": (e) ->
files = e.currentTarget.files
Cloudinary.upload files,
folder:"secret" # optional parameters described in http://cloudinary.com/documentation/upload_images#remote_upload
(err,res) -> #optional callback, you can catch with the Cloudinary collection as well
console.log "Upload Error: #{err}"
console.log "Upload Result: #{res}"
For each of the steps, I'm not sure where to place the code. For example, I don't know where I should put Cloudinary.config. Where at on the server?
Title
client
-helpers
config.js
-stylesheets
-templates
profile
profile.html
profile.js
-main.html
-main.js
lib
-collections
server
-config
*cloudinary.js
-fixtures.js
-publications.js
cloudinary.js
Cloudinary.config({
cloud_name: '***',
api_key: '***',
api_secret: '***'
});
profile.html
<template name="profile">
<div>
<form>
<input type="file" id="userimage" name="userimage"/>
<button type="submit">Upload</button>
</form>
</div>
</template>
profile.js
Template.profile.events({
// Submit signup form event
'submit form': function(e, t){
// Prevent default actions
e.preventDefault();
var file = $('#userimage')[0].files[0];
console.log(file)
Cloudinary.upload(file, function(err, res) {
console.log("Upload Error: " + err);
console.log("Upload Result: " + res);
});
}
});
let me help you.
I assume that you project structure is something like:
/main
/client
client.js
/server
server.js
Ok, lepozepo:cloudinary is written in coffescript but you can use it with vanilla javascript, so with the the folder structure showed above, you can use the following code:
client.js
$.cloudinary.config({
cloud_name: "yourname"
});
sometemplateveent({
.... some event code
Cloudinary.upload(files,{}, function(err, img) {
... do something when uploaded
});
});
and then.
server.js
Cloudinary.config({
cloud_name: 'yourname',
api_key: 'somekey',
api_secret: 'someapisecret'
});
If you need help with the submit event + upload the image you can read this post: Meteor: Cloudinary
Related
I am using CollectionFs to Upload profile pictures. Uploading and storing the image is successful. I can insert and show the image alright for one user but the
problem is:
For multiple users, when a user visit other users profiles, He sees his own picture rather than seeing the profile owner's picture!
I understand its the mongo query I have in my helper function thats causing the issue but can't just get it to work no matter how many "This._id" I Try.
Here is the javaScript
Router.route('show',{
path:'/list/:_id',
data: function(){
return Main_database.findOne({_id: this.params._id});
}
});
Template.upload.events({
'change #exampleInput':function(event, template){
var file = $('#exampleInput').get(0).files[0];
fsFile = new FS.File(file);
fsFile.metadata = {ownerId:Meteor.userId()}
Images.insert(fsFile,function(err,result){
if(!err){
console.log("New images inserted")
}
})
}
});
Template.profile.helpers({
profilePic: function () {
return Images.find({'metadata.ownerId':Meteor.userId()});
}
});
And here is the html:
<template name="upload">
<div class="container">
<div class="row">
<input type="file"
id="exampleInput">
</div>
</div>
</template>
<template name="profile">
{{#each profilePic}}
<img src="{{this.url}}"
height="400" width="400"
class="img-circle">
{{/each}}
</template>
Thanks
B.s : after following the answer given, I attached the photo in the profile.xxx field. But its still showing the wrong picture. The mongo query is still showing the wrong picture.
here is the code,
Router.route('show',{
path:'/list/:_id',
data: function(){
return Main_database.findOne({_id: this.params._id});
}
});
Template.upload.events({
'change #exampleInput':function(event, template){
var file = $('#exampleInput').get(0).files[0];
newFile = new FS.File(file);
newFile.metadata = {'ownerId':Meteor.userId()};
Images.insert(newFile,function(err,result){
if(!err){
console.log(result._id);
Meteor.users.update(Meteor.userId(),{
$set: {
'profile.profilePic': result._id
}
});
}
});
}
})
// .....................profile pic.............
Template.profile.helpers({
profilePicture: function () {
return Images.find({'_id':Meteor.user().profile.profilePic});
}
});
Finally was able to do it. Being a beginner, I was stuck at uploading images and then showing them for my users for days. Tried almost each method out there, none worked. asked everywhere, none of the answer worked. Finally , a dead simple package from cosio55:autoform-cloudinary worked like magic!!! Just take a look at the problems I faced while using these packages:
1. cfs:ui
{{#with FS.GetFile "images" selectedImageId}}
// image url
{{/with}}
problem:
with this was I couldn't get the selectedImageId .
2. cfs:gridfs
problem :
grid fs stores image in a separate collection. My user list uses iron router to show the user list form another collection. Image was getting uploaded into the images collection. But For the love of my life, I couldn't show them correctly. Each user was seeing his own picture rather than the profile owner's picture. happened because of a wrong mongo query but I couldn't get the right query. Tried attaching the photo in the profile.profilePicture, but same problem of wrong image stayed.
And I had to put the upload photo in a separate page and NOT in the autoform.
3. lepozepo:cloudinary
Problem:
Image uploaded fine. But had problem getting /storing the image url. Couldn't get
And I had to put the upload photo in a separate page and NOT in the autoform.
public_id ????? Got lost there.
4. autoform-file by yogiben
same problem as GridFs.
Finally with this cosio55:autoform-cloudinarypackage took me just a minute to figure things out. A minute vs days of other big name packages!!!!
:smiley:
<div> <img src=" {{image}}" alt=""> Image </div>
just add {{image} in the img source and thats it. The image url is stored in the same collection autoform stores everything.
Cheers Mates.
For the profilePic it will return the same user profile image, instead you should do a query by _id and not metadata.ownerId
To do that you should have a reference for the image in users collection when you insert the image something like:
Images.insert(file, function (err, res) {
if (!err) {
Meteor.users.update(Meteor.userId(),{
$set: {
'profile.profilePic': res._id,
}
});
});
And when you need to display the image you can do something like:
Template.profile.helpers({
profilePic: function () {
return Images.find({'_id':Meteor.user().profile.profilePic});
}
});
First things first: Meteor.user() and Meteor.userId() always shows data for CURRENTLY logged-in user.
So when user wants to see his own profile, it is right to use your current Template helper like this:
Template.profile.helpers({
profilePic: function () {
return Images.find({'metadata.ownerId':Meteor.userId()});
}
});
But when user goes to another user's profile, you should fetch that user's info like this: Meteor.user("another-user-id");
So how to do this? Let's suppose that you have set routing in you Meteor app with Iron Router or Flow Router and for user profile page you have set-up route path something like this: /user/:_id.
Now, you want to publish only this user's data like this in your publications on the server:
Meteor.publish("userData", function(userId){
return = Meteor.users.find({"_id": userId});
});
...and subscribe to this publication on client (we'll use Template-level subscriptions!)
With Iron Router:
var userId;
Template.profile.onCreated(function() {
var self = this;
self.autorun(function() {
userId = Router.current().params._id;
self.subscribe("userData", userId);
}
});
Template.profile.helpers({
profilePic: function () {
return Images.find({'metadata.ownerId': userId});
}
});
With FlowRouter:
var userId;
Template.profile.onCreated(function() {
var self = this;
self.autorun(function() {
userId = FlowRouter.getParam("_id");
self.subscribe("userData", userId);
}
});
Template.profile.helpers({
profilePic: function () {
return Images.find({'metadata.ownerId': userId});
}
});
I have the following code on my Meteor app.
main.js (partial):
Template.login.events({
'click .login-button': function( e ) {
var serviceName = e.currentTarget.id.replace( 'login-buttons-', '' );
Accounts._loginButtonsSession.resetMessages();
var loginWithService = Meteor["loginWith" + (serviceName === 'meteor-developer' ? 'MeteorDeveloperAccount' : capitalize(serviceName))];
var options = {}; // use default scope unless specified
if (Accounts.ui._options.requestPermissions[serviceName])
options.requestPermissions = Accounts.ui._options.requestPermissions[serviceName];
if (Accounts.ui._options.requestOfflineToken[serviceName])
options.requestOfflineToken = Accounts.ui._options.requestOfflineToken[serviceName];
if (Accounts.ui._options.forceApprovalPrompt[serviceName])
options.forceApprovalPrompt = Accounts.ui._options.forceApprovalPrompt[serviceName];
loginWithService(options, function (err) {
console.log('user logged in');
});
}
})
And index.html (partial):
<div class="service-login-buttons">
<div class="login-text-and-button">
<div class="login-button single-login-button" id="login-buttons-twitter">
<div class="login-image" id="login-buttons-image-twitter"></div>
<span class="text-besides-image sign-in-text-twitter">Sign in to save your Pomodoros</span>
</div>
</div>
</div>
On the localhost it works just fine (twitter login).
I changed the twitter app settings to point to the correct *.meteor.com address, but the button doesn't do anything (no errors either).
Is there perhaps some configuration I need to redo?
The answer is simple: I had to configure the Twitter API on the deployed version as well.
Since I was using custom login buttons, I simply added
{{> loginButtons }}
To get the configuration dialog (where the API keys are added), then removed that part after configuration was done.
I am confused about something.
I am trying to use the dropzone.js meteor package (http://atmospherejs.com/dbarrett/dropzonejs) with my meteor application but I could not find any example about it. In the documentation it says:
Use the template like this
{{> dropzone url='http://somewebsite.com/upload' id='dropzoneDiv'}}
and
it will post any uploaded files to the url of your choice.
So if I write,
{{> dropzone url='http://localhost:3000/home' id='dropzoneDiv'}}
as soon as I drop the image, is it going to upload it to /public/home folder? I mean is the package handling server-side saving image too?
If not, can you please give me some tips about how I can handle the server side saving?
Thank you
Dropzone can be a bit confusing:
First you should get a file management system for Meteor. The standard right now is CollectionFS:
https://github.com/CollectionFS/Meteor-CollectionFS
Then you need to add a file system. I use GridFS, which breaks up large files into chunks and stores them for you into Mongo:
https://github.com/CollectionFS/Meteor-cfs-gridfs/
Follow the instructions for creating, publishing, and subscribing to your new, special, FS Collection:
example for creating the collection:
MyImages = new FS.Collection('myImages', {
stores: [new FS.Store.GridFS("myImages")]
});
After those two are installed, create your dropzone:
<template name="imageUpload">
<form action="/file-upload" class="dropzone" id="dropzone"></form>
</template>
Then in your javascript:
Template.imageUpload.rendered = function(){
if (Meteor.isClient){
var arrayOfImageIds = [];
Dropzone.autoDiscover = false;
// Adds file uploading and adds the imageID of the file uploaded
// to the arrayOfImageIds object.
var dropzone = new Dropzone("form#dropzone", {
accept: function(file, done){
MyImages.insert(file, function(err, fileObj){
if(err){
alert("Error");
} else {
// gets the ID of the image that was uploaded
var imageId = fileObj._id;
// do something with this image ID, like save it somewhere
arrayOfImageIds.push(imageId);
};
});
}
});
};
};
I'm assuming, it doesn't show upload progress, because its instant with meteor.
You are updating mini-mongo location in-browser, so the changes are immediate.
Meteor DDP then handles the glue to get it to the server, and then pushing those changes to the other clients that might be subscribed. That "instant" update is the meteor magic. Alert yourself, or log to console on success. You can also check the db via MyImages.find().fetch().
If they are there, all done.
Please find below link(example of dropzonejs):
https://github.com/devonbarrett/meteor-dropzone/tree/master/example-app
Put {{>dropzone url="/upload" id="template-helper"}} In your template
<template name="test">
{{>dropzone url="/upload" id="template-helper"}}
</template>
Then at server side:
if (Meteor.isServer) {
Meteor.startup(function () {
UploadServer.init({
tmpDir: process.env.PWD + '/public/uploads',
uploadDir: process.env.PWD + '/public/uploads',
checkCreateDirectories: true,
uploadUrl: '/upload'
});
});
}
I create these two local collections (the code is actually written one after the other exactly like below):
ShoppingCartCollection = new Meteor.Collection(null);
CurrentPricesCollection = new Meteor.Collection(null);
Inside Template.myTemplate.rendered I add some initial info into these collections (again, code is one after the other):
ShoppingCartCollection.insert({"sqft" : "not yet entered"});
CurrentPricesCollection.insert({"hdrPhotos" : 100});
I've got these two global helpers in helpers.js (defined one after the other)
Handlebars.registerHelper("shoppingCart", function() {
return ShoppingCartCollection.findOne();
});
Handlebars.registerHelper("currentPrice", function() {
return CurrentPricesCollection.findOne();
});
When I load the page I immediately run these commands in the console:
> ShoppingCartCollection.findOne();
Object {sqft: "not yet entered", _id: "xcNmqJvMqqD5j7wwn"}
> CurrentPricesCollection.findOne();
Object {hdrPhotos: 100, _id: "LP38E3MZgzuYjvSec"}
In my template I use these helpers, but...
{{currentPrice.hdrPhotos}} //displays nothing
{{shoppingCart.sqft}} //displays "not yet entered"
How... what... ? How can this be? Are there some kind of gotchas that I could be missing? Some kind of dependency or load order that I'm not aware of?
The code you posted is working fine here.
Suggest comparing this code to the exact details of what you are doing. Also, look
for other problems, typos, etc.
Below is the exact test procedure I used:
From nothing, at the linux console:
meteor create sodebug
Note that this will produce files for a "hello world" type program.
Check the version:
meteor --version
Release 0.8.1.1
Edit sodebug/sodebug.js:
if (Meteor.isClient) {
// code autogenerated by meteor create
Template.hello.greeting = function () {
return "Welcome to sodebug.";
};
Template.hello.events({
'click input': function () {
// template data, if any, is available in 'this'
if (typeof console !== 'undefined')
console.log("You pressed the button");
}
});
// add your code here
ShoppingCartCollection = new Meteor.Collection(null);
CurrentPricesCollection = new Meteor.Collection(null);
ShoppingCartCollection.insert({"sqft" : "not yet entered"});
CurrentPricesCollection.insert({"hdrPhotos" : 100});
Handlebars.registerHelper("shoppingCart", function() {
return ShoppingCartCollection.findOne();
});
Handlebars.registerHelper("currentPrice", function() {
return CurrentPricesCollection.findOne();
});
}
if (Meteor.isServer) {
Meteor.startup(function () {
// code to run on server at startup
});
}
Edit sodebug.html:
<head>
<title>sodebug</title>
</head>
<body>
{{> hello}}
{{> T1 }}
{{> T2 }}
</body>
<template name="T1">
<p>
{{shoppingCart.sqft}}
</p>
</template>
<template name="T2">
<p>
{{currentPrice.hdrPhotos}}
</p>
</template>
<template name="hello">
<h1>Hello World!</h1>
{{greeting}}
<input type="button" value="Click" />
</template>
Run: meteor run
Manual tests:
Fire up chromium browser at localhost:3000
Check web browser console for collections data. PASS
Check web browser screen for templates data. PASS
Reorder templates in sodebug.html file, check web browser screen. PASS
I have followed collectionFS guide and several other stackoverflow questions [here][1], but I still face an error in displaying the image. The broken image icon is shown and console prints "Resource interpreted as Image but transferred with MIME type text/html:". Any idea what i can do to solve this??
My code are as follows:
HTML
<template name="fileList">
{{#each images}}
{{name}}
<img src="{{cfsFileUrl 'default1'}}">
<br />
{{else}}
No Files uploaded
{{/each}}
</template>
Client JS
Template.fileList.helpers({
'images': function(){
return ImagesFS.find({}, {sort: {uploadDate:-1}});
}
});
Server JS
if(Meteor.isServer){
ImagesFS.fileHandlers({
default1: function(options) { // Options contains blob and fileRecord — same is expected in return if should be saved on filesytem, can be modified
console.log('I am handling default1: ' + options.fileRecord.filename);
console.log(options.destination());
return { blob: options.blob, fileRecord: options.fileRecord }; // if no blob then save result in fileHandle (added createdAt)
}
});
}
I got this working by manually adding the cfs-public-folder package via:
meteor add cfs-public-folder
Now files show in the browser, and the URL to
http://localhost:3000/cfs/<collectionFS name>/<imageId_fileHandler.ext>
works.
cfs-public-folder
is not working anymore on 0.9.x
please use:
.url()
like
MyColletionCFS.findOne().url()