In my meteor app I am uploading images and storing them in dropbox. It works fine when I am running the app in localhost. But as soon as I run the app after deploying it to meteor.com the upload fails to work.
This is my code in server.js
var createThumb = function(fileObj, readStream, writeStream) {
// Transform the image into a 10x10px thumbnail
gm(readStream, fileObj.name()).resize('10', '10').stream().pipe(writeStream);
};
var dropboxStore = new FS.Store.Dropbox("files", {
key: "",
secret: "",
token: "", // Don’t share your access token with anyone.
transformWrite: createThumb, //optional
})
Images = new FS.Collection("files", {
stores: [dropboxStore]
});
Images.allow({
'insert': function () {
// add custom authentication code here
return true;
}
});
Here is the link to meteor.com http://image_upload.meteor.com/.
I have tried changing dropbox to s3 but it still doesn't work. Could it be because it is hosted at meteor.com?
Looking forward for a solution.
Most likely it's because you're trying to use GraphicsMagick to resize the image in the transformWrite option, but meteor.com hosting servers do not have GraphicsMagick or ImageMagick installed.
https://github.com/CollectionFS/Meteor-CollectionFS/issues/299
You can use the meteor logs command to view the logs from your hosted meteor.com application to make sure that's the issue.
Edit
Here's some sample code for the jQuery cropper utility:
Template HTML:
<input type="file" style="visibility:hidden;width:1px" accept="image/gif, image/jpeg, image/png" class="profilePhotoFile">
<input type="button" id="btnEditPhoto" value="Edit Photo" class="btn btn-primary" style="width:160px"/>
<div class="modal fade" id="cropper-modal">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-body">
<div id="cropper">
<img src="" alt="Picture">
</div>
</div>
<div class="modal-footer">
<button class="btn btn-primary" id="btnSavePhoto">Save</button>
<button class="btn btn-default" id="btnCancel">Cancel</button>
</div>
</div>
</div>
</div>
Template JS:
Template.myTemplate.events({
'click #btnEditPhoto': function(event, template) {
$('.profilePhotoFile').click();
},
'change .profilePhotoFile': function(event, template) {
if (!event.target.files || event.target.files.length === 0) {
return;
} else {
var $inputImage = $(event.target);
var URL = window.URL || window.webkitURL;
var file = event.target.files[0];
var blobURL = URL.createObjectURL(file);
$image = $('#cropper > img');
$('#cropper-modal').modal();
$('#cropper-modal').on('shown.bs.modal', function() {
$image.cropper({
aspectRatio: 1.0,
autoCropArea: 1.0
}).cropper('replace', blobURL);
$inputImage.val('');
}).on('hidden.bs.modal', function() {
$image.cropper('destroy');
URL.revokeObjectURL(blobURL); // Revoke url
});
}
},
'click #btnSavePhoto': function(event, template) {
$image = $('#cropper > img');
//Change the width and height to your desired size
var base64EncodedImage = $image.cropper('getCroppedCanvas', {width: 10, height: 10}).toDataURL('image/jpeg');
$('#cropper-modal').modal('hide');
var newImage = new FS.File(base64EncodedImage);
Images.insert(newImage, function(err, fileObj) {
if (err) {
console.log(err);
} else {
//do something after insert
}
});
},
'click #btnCancel': function(event, template) {
$('#cropper-modal').modal('hide');
}
});
Related
I am working on a small VueJS app that pulls in WordPress posts via the API. Everything works great with pagination to load more posts, however I am not too sure how I can reset the entire XHR getPosts method when you change the user ID radio field.
When you change the author ID currently, it will not reset the results. I believe it should be something in the watch: area to destroy the current page - but not too sure. Thanks!
https://codepen.io/sco/pen/aRwwGd
JS
Vue.component("posts", {
template: `
<ul>
<slot></slot>
</ul>
`
});
Vue.component("post", {
props: ["title", "excerpt", "permalink"],
template: `
<li>
<h3 v-html="title"></h3>
<div v-if="excerpt" v-html="excerpt"></div>
<a :href="permalink">Read More</a>
</li>
`
});
var App = new Vue({
el: "#app",
data: {
greeting: "Load more Posts Vue + WP REST API",
page: 0,
posts: [],
totalPages: "",
apiURL: "https://poststatus.com/wp-json/wp/v2/posts/?per_page=2",
isLoading: "",
show: true,
authors: [1, 590],
currentAuthor: ""
},
watch: {
currentAuthor: "fetchData"
},
methods: {
getPosts: function() {
var xhr = new XMLHttpRequest();
var self = this;
self.page++;
self.isLoading = "is-loading";
xhr.open(
"GET",
self.apiURL + "&page=" + self.page + "&author=" + self.currentAuthor
);
xhr.onload = function() {
self.totalPages = xhr.getResponseHeader("X-WP-TotalPages");
if (self.page == self.totalPages) {
self.show = false;
}
var newPosts = JSON.parse(xhr.responseText);
newPosts.forEach(function(element) {
self.posts.push(element);
});
self.isLoading = null;
//console.log(self.apiURL + self.page)
};
xhr.send();
}
}
});
HTML
<section id="app" class="wrapper">
<div class="container">
<div class="box">
<template v-for="author in authors">
<div class="author-toggle">
<input type="radio"
:id="author"
:value="author"
name="author"
v-model="currentAuthor">
<label :for="author">{{ author }}</label>
</div>
</template><br>
<h3 v-if="page>0">Showing Page {{page}} of {{totalPages}}</h3>
<progress v-if="page>0" class="progress" :value="page" :max="totalPages">{{page}}</progress>
<posts v-if="posts">
<post v-for="post in posts" class="post" :id="'post' + post.id" :title="post.title.rendered" :permalink="post.link" :key="post.id">
</post>
</posts>
<button :class="isLoading + ' ' +'button is-primary'" v-if="show" #click="getPosts(page)">Load Posts</button>
</div>
</div>
</section>
You can reset page, posts, and totalPages inside the watcher:
watch: {
currentAuthor() {
this.page = 0;
this.totalPages = 0;
this.posts = [];
this.getPosts();
}
}
your codepen with required changes
I'm attempting to tie Blueimp File Uploader into my MVC 5 solution. I have the uploads working as follows:
<span class="btn btn-success fileinput-button">
<i class="glyphicon glyphicon-plus"></i>
<span>Add files...</span>
<input id="fileupload" type="file" name="files[]" multiple>
</span>
<br />
<div class="progress">
<div class="progress-bar" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width: 0%;">
<span class="sr-only">0% complete</span>
</div>
</div>
<br />
<div class="file_name"></div>
<br />
<div class="file_type"></div>
<br />
<div class="file_size"></div>
<!-- The container for the uploaded files -->
<div id="files" class="files"></div>
and the javascript
$(document).ready(function () {
var Url = "#Url.Content("~/Advertise/UploadFiles")";
$('#fileupload').fileupload({
dataType: 'json',
url: Url,
autoUpload: true,
done: function (e, data) {
// $('.file_name').html(data.result.name);
// $('.file_type').html(data.result.type);
// $('.file_size').html(data.result.size);
}
}).on('fileuploadadd', function (e, data) {
data.context = $('<div/>').appendTo('#files');
$.each(data.files, function (index, file) {
var node = $('<p/>')
.append('<img src="' + URL.createObjectURL(data.files[0]) + '" height="50" width="50"/>').append($('<span/>').text(file.name));
if (!index) {
node
.append('<br>')
//.append(uploadButton.clone(true).data(data));
}
node.appendTo(data.context);
});
}).on('fileuploadprocessalways', function (e, data) {
var index = data.index,
file = data.files[index],
node = $(data.context.children()[index]);
if (file.preview) {
node
.prepend('<br>')
.prepend(file.preview);
}
if (file.error) {
node
.append('<br>')
.append($('<span class="text-danger"/>').text(file.error));
}
if (index + 1 === data.files.length) {
data.context.find('button')
.text('Upload')
.prop('disabled', !!data.files.error);
}
}).on('fileuploadprogressall', function (e, data) {
var progress = parseInt(data.loaded / data.total * 100, 10);
$('#progress .progress-bar').css(
'width',
progress + '%'
);
}).on('fileuploaddone', function (e, data) {
$.each(data.result.files, function (index, file) {
if (file.url) {
var link = $('<a>')
.attr('target', '_blank')
.prop('href', file.url);
$(data.context.children()[index])
.wrap(link);
} else if (file.error) {
var error = $('<span class="text-danger"/>').text(file.error);
$(data.context.children()[index])
.append('<br>')
.append(error);
}
});
}).on('fileuploadfail', function (e, data) {
$.each(data.files, function (index) {
var error = $('<span class="text-danger"/>').text('File upload failed.');
$(data.context.children()[index])
.append('<br>')
.append(error);
});
}).prop('disabled', !$.support.fileInput)
.parent().addClass($.support.fileInput ? undefined : 'disabled');
});
I've not tested a lot of the jQuery above. But I'm looking in to how I can delete an uploaded file? I could probably do it by calling a jQuery ajax post, but I think Blueimp has a native way to do it. But I can't find any documentation on it?? Any help appreciated.
I am trying to use Google Picker within a Meteor application. I am not an expert, I just followed the example on Google Picker API page https://developers.google.com/picker/docs/index but could not make it work.
Here is what I tried in the client side and of course I changed the devKey and Client ID:
// The Browser API key obtained from the Google Developers Console.
var developerKey = 'AIzaSyC9gfrgtnj6fd00hDau3B0LSTqajeDIyl0';
// The Client ID obtained from the Google Developers Console. Replace with your own Client ID.
var clientId = "582812345678-5t9joqkb5d1rfders25fhr5u6k28s9lc.apps.googleusercontent.com"
// Scope to use to access user's photos.
var scope = ['https://www.googleapis.com/auth/photos'];
var pickerApiLoaded = false;
var oauthToken;
Template.gPicker.helpers({
// Use the API Loader script to load google.picker and gapi.auth.
onApiLoad : function() {
gapi.load('auth', {'callback': onAuthApiLoad});
gapi.load('picker', {'callback': onPickerApiLoad});
},
onAuthApiLoad : function() {
window.gapi.auth.authorize(
{
'client_id': clientId,
'scope': scope,
'immediate': false
},
handleAuthResult);
},
onPickerApiLoad : function() {
pickerApiLoaded = true;
createPicker();
},
handleAuthResult : function(authResult) {
if (authResult && !authResult.error) {
oauthToken = authResult.access_token;
createPicker();
}
},
// Create and render a Picker object for picking user Photos.
createPicker : function() {
if (pickerApiLoaded && oauthToken) {
var picker = new google.picker.PickerBuilder().
addView(google.picker.ImageSearchView).
setOAuthToken(oauthToken).
setDeveloperKey(developerKey).
setCallback(pickerCallback).
build();
picker.setVisible(true);
}
},
// A simple callback implementation.
pickerCallback : function(data) {
var url = 'nothing';
if (data[google.picker.Response.ACTION] == google.picker.Action.PICKED) {
var doc = data[google.picker.Response.DOCUMENTS][0];
url = doc[google.picker.Document.URL];
}
var message = 'You picked: ' + url;
document.getElementById('result').innerHTML = message;
}
});
Then on the template:
<head>
<title>imagesearch</title>
</head>
<body>
{{> gPicker}}
<script type="text/javascript" src="https://apis.google.com/js/api.js?onload=onApiLoad"></script>
</body>
<template name="gPicker">
<div class="col-lg-6">
<div class="input-group">
<input type="text" class="form-control recherche">
<span class="input-group-btn">
<button class="btn btn-default" type="button">Go!</button>
</span>
</div>
</div>
<div id="result"></div>
</template>
I am basically trying to upload a file using angular and a webmethod.
I took the code from this blog but it does not work. The request is successfull as seen from fiddler but the web method never gets invoked.
Am I doing something wrong?
Following is my code .
angular
.module('loader', ['ui.router', 'ui.bootstrap', 'ui.filters'])
.controller('loader-main', function($rootScope, $scope, WebServices) {
$scope.uploadNewFile = function() {
WebServices.uploadFile($scope.myfile);
}
}).factory('WebServices', function($rootScope, $http) {
return {
postFile: function(method, uploadData) {
var uploadUrl = "myASPXPAGE.aspx/" + method;
return $http.post(uploadUrl, uploadData, {
transformRequest: angular.identity,
headers: {
'Content-Type': undefined
}
}).success(function(data) {
///Control reaches here but never hits the server method
});
},
uploadFile: function(filedata) {
var fd = new FormData();
fd.append('file', filedata);
return this.postFile("UploadFile", fd);
}
};
}).directive('fileModel', ['$parse',
function($parse) {
return {
restrict: 'A',
link: function($scope, element, attr) {
var model = $parse(attr.fileModel);
var modelSetter = model.assign;
element.bind('change', function() {
$scope.$apply(function() {
modelSetter($scope, element[0].files[0]);
});
});
}
}
}
]);
<div class="row">
<div class="col-xs-5">
<div class="col-xs-4">Browse to File:</div>
<div class="col-xs-1">
<input type="file" id="uploadFile" class="btn btn-default" file-model="myfile" />
<input type="button" class="btn btn-primary" value="Load File" data-ng-click="uploadNewFile()" />
</div>
</div>
</div>
And here is my WebMethod
[WebMethod]
public static string UploadFile()
{
System.Diagnostics.Debugger.Break();
return "Done";
}
Figured it out. You cannot have Content-Type as multipart/form-data in webmethods. Instead created a HttpHandler to upload the file and everything works just fine.
I am having a little bit of trouble outputting a image after a filepicker selection with the file picker plus package from meteor. How to I grab the uploaded image url or file path, so I can pass it into a form input and put it in a collection. Putting in into the collection isnt the part I am worried about its getting the path that I am having trouble with cheers.
All contained in postSubmit template.
I have a form with
<input type="filepicker" name="myName" />
and a img output in the same template
<img src="{{filepickerIdToUrl myName}}">
and a router file containg
Router.onBeforeAction(function(){
loadFilePicker('magickey');
//can leave out key if its in settings
this.next();
},{only:['postSubmit']});
Here is the full postSubmit template
<template name="postSubmit">
<form>
<label for="title">Title</label>
<input name="title" id="title" type="text" value="" placeholder="Name your post"/>
<button id="uploadImage" class="btn btn-info btn-sm"><i class="fa fa-upload"></i> Upload</button>
<input type="submit" value="Submit"/>
</form>
<img id="imagePreview" class="img-responsive" src="{{filepickerIdToImageUrl imageId placehold_it='500x350' h=200 w=300}}"/>
<button id="removeImage" class="btn btn-warning btn-sm"><i class="fa fa-trash-o"></i> Remove</button>
This is also my postSubmit events
Template.postSubmit.events({
'submit form': function(e) {
e.preventDefault();
var post = {
title: $(e.target).find('[name=title]').val(),
image: $(e.target).find('[name=image]').val()
};
Meteor.call('postInsert', post, function(error, result) {
// display the error to the user and abort
if (error)
return alert(error.reason);
Router.go('postPage', {_id: result._id});
});
}
});
Thanks to Nate and the google groups link above, I got it working.
Here is my solved code, Right now it only shows the preview on the form and you can remove it by clearing the session value, but it will be easy enough to grab that session value and put it into the form on submit.
Thanks again Nate.
Template.postSubmit.created = function(){
Session.setDefault("imageId", null);
Session.setDefault("imageKey", null);
};
Template.postSubmit.events({
'submit form': function(e) {
e.preventDefault();
var post = {
title: $(e.target).find('[name=title]').val(),
image: $(e.target).find('[name=image]').val()
};
Meteor.call('postInsert', post, function(error, result) {
// display the error to the user and abort
if (error)
return alert(error.reason);
Router.go('postPage', {_id: result._id});
});
},
'click #uploadImage':function(event, template){
event.preventDefault();
filepicker.pickAndStore(
{
mimetypes: ['image/gif','image/jpeg','image/png'],
multiple: false
},{
access:"public"
},
function(InkBlobs){
// the upload is now complete to filepicker - but the form hasnt persisted the values to our collection yet
Session.set("imageId", _.last(_.first(InkBlobs).url.split("/")));
Session.set("imageKey", _.first(InkBlobs).key);
// once the session changes are made, the form will now have the new values, including a preview of the image uploaded
},
function(FPError){
log.error(FPError.toString());
}
);
},
'click #removeImage':function(event, template){
event.preventDefault();
Session.set("imageId", "remove");
Session.set("imageKey", "remove");
}
});
Template.postSubmit.helpers({
'hideRemove':function(){
return Session.equals("imageId", null) || Session.equals("imageId", "remove");
},
'imageId':function(){
if(Session.equals("imageId", "remove"))
return "";
else
return Session.get("imageId") || "";
},
'imageKey':function(){
if(Session.equals("imageKey", "remove"))
return "";
else
return Session.get("imageKey") || "";
}
});