Meteor file upload not working - javascript

I'm trying to upload images via Meteors CollectionFS but I'm not getting any errors in the client side code so I'm not sure what's broken. I see the console.log message "inside upload" but I don't see any success or fail messages from the Images.insert callback. Help.
myproject/client/upload.html
<template name="upload">
<form>
<input class="upload" type="file" id="upload" name=".../">
</form>
</template>
myproject/client/upload.js
Template.providerblock.events({
'click .upload': function(event, template) {
event.preventDefault();
var photo = $('#upload')[0];
var file = photo.files[0];
console.log("inside upload");
Images.insert(file, function (err, fileObj) {
if(err) {
console.log("unable to upload file");
} else {
console.log("file upload success");
}
});
},
});
myproject/lib/images.js
var Images = new FS.Collection("images", {
stores: [new FS.Store.FileSystem("images", {path: "~/uploads"})]
});
Images.allow({
insert: function() {
return true;
},
update: function() {
return true;
},
remove: function() {
return true;
},
download: function() {
return true;
}
});

You should:
Use 'change .upload': instead of 'click .upload':.
Images instead of var Images so you can use the variable in other file.

Related

Invoking handler multiple times on file-input change

I needed to create a button that will trigger an input-file and invoke the handler & AJAX when file was chosen:
<template>
<button id="ImportExcelBtn" type="button" class="ladda-button" data-color="mint" data-style="zoom-out" data-size="sm">
<span class="ladda-label">Import Excel</span>
<div class="hidden">
<input type="file" id="fileUpload" #change="handleFileUpload">
</div>
</button>
<script>
export default {
props: {
tablename: String,
modelname: String
},
data: function() {
return {
recursive: true,
file: {}
}
},
methods: {
handleFileUpload: function(e) {
var self = this;
self.file = e.target.files[0];
self.importExcel();
},
importExcel: function() {
var self = this;
self.recursive = true;
var bodyFormData = new FormData();
bodyFormData.set('tablename', self.tablename);
bodyFormData.append('file', self.file);
Services.importExcel(bodyFormData).then(function(response) {
if(response.data.status == 'failed'){
Global.ErrorMessages(response.data.messages);
} else {
console.log('all right');
}
}).catch(function(error) {
var error = Object.assign({}, error);
console.log(error);
Global.ErrorMessages(error.response);
});
}
},
mounted: function() {
var self = this;
$(document).ready(function () {
$('#ImportExcelBtn').click(function() {
if(self.recursive){
self.recursive = false;
$('#fileUpload').click();
}
});
})
}
}
At first go, this works perfectly, but if I chose another file to upload, than the handler isn't invoked when the file is chosen unless I click the button for the third time.
Please note that the input most be inside the button for system purposes, so taking it outside of the button and putting them both in a div is not an option...
Check all the assignments of the recursive, please. If you click on the button and then cancel choosing a file that leads to the recursive would be false and afterwards the "click" handler does nothing.

Cordova File API saving file to memory card

Firstly why in gods name is there no tutorial for this even Cordova's guides don't tell you how to save a flaming file to a location on the phone.
(function(w){
function FileServices(FileName, callb){
var self = this;
var isFileOpen = false;
var fileHandler;
// open file handle
function OpenFile(callb){
window.requestFileSystem(LocalFileSystem.PERSISTENT, 5*1024, function (fs) {
fs.root.getFile(cordova.file.externalDataDirectory+FileName, { create: true, exclusive: false }, function (fileEntry) {
fileHandler = fileEntry;
isFileOpen = true;
callb(self, fileHandler);
});
}, function(e,c){console.log(e,c);});
}
// write to file
function WriteFile(fileEntry, dataObj, isAppend, callback) {
// Create a FileWriter object for our FileEntry (log.txt).
fileEntry.createWriter(function (fileWriter) {
fileWriter.onerror = function (e) {
};
// If we are appending data to file, go to the end of the file.
if (isAppend) {
try {
fileWriter.seek(fileWriter.length);
}
catch (e) { }
}
fileWriter.write(dataObj);
callback(self, fileWriter);
});
}
this.writeLine = function(txt, append, callback){
if(isFileOpen){
WriteFile(fileHandler, new Blob([txt], { data:'plain/text' }), append, callback);
}
}
OpenFile(callb);
};
// add to the navigator when device ready
document.addEventListener("deviceready", function(){
navigator.FileServices = function GetFileServices(FileName, callback){
return new FileServices(FileName, callback);
}
});
})(window);
All i get is "Error Code 5 = FileError.ENCODING_ERR";
I can't work it out....

angular doesn't print data after scanning qr

I'm working with NativeStorage and barcodeScanner plugins for cordova.
The capture works well, and I receive the QRCode, but for any reason angular doesn't print it.
After working a lot on my code, I'm not able to do a valid callback, so angular can print it binding the data.
Here bellow I paste the code.
read.js
(function() {
'use strict';
var read = angular.module('app.read', ['monospaced.qrcode']);
read.controller('ReadController', [
function() {
var data = this;
var qr = function(string) {
data.code = string;
console.log(string);
};
cordova.plugins.barcodeScanner.scan(
function(result) {
if (!result.cancelled) {
if (result.format === "QR_CODE") {
(function(cb) {
cb(result.text);
})(qr);
NativeStorage.getItem("historic", function(d) {
var storage = JSON.parse(d);
storage.push(result.text);
NativeStorage.setItem("historic", JSON.stringify(storage), function(response) {}, function(e) {
console.log(e);
});
}, function(e) {
window.alert("Scanning failed: " + e);
});
}
}
},
function(e) {
window.alert("Scanning failed: " + e);
}, {
"preferFrontCamera": true, // iOS and Android
"showFlipCameraButton": true, // iOS and Android
"prompt": "Place a barcode inside the scan area", // supported on Android only
"formats": "QR_CODE,PDF_417", // default: all but PDF_417 and RSS_EXPANDED
"orientation": "portrait" // Android only (portrait|landscape), default unset so it rotates with the device
}
);
}
]);
}());
read.html
<div ng-controller="ReadController as myRead">
<qrcode version="5" error-correction-level="H" size="200" data="{{myRead.code}}" href="{{myRead.code}}"></qrcode>
{{myRead.code}}
</div>
Just adding some extra tests I have done before, I just missed the barcodeScanner.scan process and I did just the storage as I show bellow:
NativeStorage.getItem("historic", function (d) {
var storage = JSON.parse(d);
storage.push('https://google.es');
data.code = 'https://google.es';
NativeStorage.setItem("historic", JSON.stringify(storage), function (response) {}, function (e) {
console.log(e);
});
}, function (e) {
window.alert("Scanning failed: " + e);
});
Could you show me where am I wrong?
Thanks in advice.
A qualified guess is that the callbacks from cordova.plugins.barcodeScanner.scan doesn't trigger AngularJS' digest cycle, which means no dirty checking will be performed, no changes will be detected and the UI won't be updated.
Try wrapping the code in the success callback in $apply:
function(result) {
$scope.$apply(function() {
if (!result.cancelled) {
if (result.format === "QR_CODE") {
(function(cb) {
cb(result.text);
})(qr);
NativeStorage.getItem("historic", function(d) {
var storage = JSON.parse(d);
storage.push(result.text);
NativeStorage.setItem("historic", JSON.stringify(storage), function(response) {}, function(e) {
console.log(e);
});
}, function(e) {
window.alert("Scanning failed: " + e);
});
}
}
});
}

How to show content of collection to other users?

At first I am a beginner in meteor. I am creating an app for school. Users can add something to a collection. My problem is that only the author sees the task at the moment. How can i fix it?
Edit: My js code
if (Meteor.isClient)
{
Template.Collection.onCreated(function() {
var self = this;
self.autorun(function() {
self.subscribe('tasks');
});
});
Template.Collection.helpers({
tasks: ()=> {
return tasks.find({inCollection: true});
}
});
Template.Tasks.onCreated(function() {
var self = this;
self.autorun(function() {
self.subscribe('tasks');
});
});
Template.tasks.helpers({
tasks: ()=> {
return tasks.find({});
}
});
Template.Tasks.events({
'click .new-task': () => {
Session.set('newTask', true);
}
});
Template.TaskSingle.onCreated(function() {
var self = this;
self.autorun(function() {
var id = FlowRouter.getParam('id');
self.subscribe('singleTask', id);
});
});
Template.TaskSingle.helpers({
task: ()=> {
var id = FlowRouter.getParam('id');
return Tasks.findOne({_id: id});
}
});
Template.NewTask.events({
'click .fa-close' : function() {
Session.set('newTask', false);
}
});
Template.Task.onCreated(function(){
this.editMode = new ReactiveVar(false);
// this.editMode = new ReactiveVar();
//this.editMode.set(false);
});
Template.Task.helpers({
updateTaskId: function() {
return this._id;
},
editMode: function() {
return Template.instance().editMode.get();
}
});
Template.Task.events({
'click .toggle-menu': function() {
Meteor.call('toggleMenuItem', this._id, this.inCollection);
},
'click .fa-trash' : function() {
Meteor.call('deleteTask', this._id);
},
'click .fa-pencil' : function(event, template) {
template.editMode.set(!template.editMode.get());
}
});
}
if (Meteor.isServer) {
Meteor.startup(function () {
//code to run on server at startup
});
Meteor.publish('tasks', function(){
return tasks.find({author: this.userId});
});
Meteor.publish('singleTask', function(id){
check(id, String);
return Tasks.find({_id: id});
});
// Configure Accounts to require username instead of email
Accounts.ui.config({
passwordSignupFields: "USERNAME_ONLY"
});
}
If you've removed the autopublish package then documents then you need to create publications and subscriptions for documents to be sent to clients.
On the server you write: Meteor.publish('items', function () { return Items.find(); }.
And on the client you would subscribe with Meteor.subscribe('items');.
You clearly publish the tasks for the author only:
Meteor.publish('tasks', function(){
return Tasks.find({author: this.userId});
});
If you want it to be visible to everyone, it should be
Meteor.publish('tasks', function(){
return Tasks.find();
});

GUI component for display async request states

Which interface or component do you suggest to display the state of parallel async calls? (The language is not so important for me, just the pattern, I can rewrite the same class / interface in javascript...)
I load model data from REST service, and I want to display pending label before the real content, and error messages if something went wrong... I think this is a common problem, and there must be an already written component, or best practices, or a pattern for this. Do you know something like that?
Here is a spaghetti code - Backbone.syncParallel is not an existing function yet - which has 2 main states: updateForm, updated. Before every main state the page displays the "Please wait!" label, and by error the page displays an error message. I think this kind of code is highly reusable, so I think I can create a container which automatically displays the current state, but I cannot decide what kind of interface this component should have...
var content = new Backbone.View({
appendTo: "body"
});
content.render();
var role = new Role({id: id});
var userSet = new UserSet();
Backbone.syncParallel({
models: [role, userSet],
run: function (){
role.fetch();
userSet.fetch();
},
listeners: {
request: function (){
content.$el.html("Please wait!");
},
error: function (){
content.$el.html("Sorry, we could not reach the data on the server!");
},
sync: function (){
var form = new RoleUpdateForm({
model: role,
userSet: userSet
});
form.on("submit", function (){
content.$el.html("Please wait!");
role.save({
error: function (){
content.$el.html("Sorry, we could not save your modifications, please try again!");
content.$el.append(new Backbone.UI.Button({
content: "Back to the form.",
onClick: function (){
content.$el.html(form.$el);
}
}));
},
success: function (){
content.$el.html("You data is saved successfully! Please wait until we redirect you to the page of the saved role!");
setTimeout(function (){
controller.read(role.id);
}, 2000);
}
});
}, this);
form.render();
content.$el.html(form.$el);
}
}
});
I created a custom View to solve this problem. (It is in beta version now.)
Usage: (Form is a theoretical form generator)
var content = new SyncLabelDecorator({
appendTo: "body",
});
content.load(function (){
this.$el.append("normal html without asnyc calls");
});
var User = Backbone.Model.extend({
urlRoot: "/users"
});
var UserSet = Backbone.Collection.extend({
url: "/users",
model: User
});
var Role = Backbone.RelationalModel.extend({
relations: [{
type: Backbone.HasMany,
key: 'members',
relatedModel: User
}]
});
var administrator = new Role({id :1});
var users = new UserSet();
content.load({
fetch: [role, users],
sync: function (){
var form = new Form({
title: "Update role",
model: role,
fields: {
id: {
type: "HiddenInput"
},
name: {
type: "TextInput"
},
members: {
type: "TwoListSelection",
alternatives: users
}
},
submit: function (){
content.load({
tasks: {
save: role
},
sync: function (){
this.$el.html("Role is successfully saved.");
}
});
}
});
this.$el.append(form.render().$el);
}
});
Code:
var SyncLabelDecorator = Backbone.View.extend({
options: {
pendingMessage: "Sending request. Please wait ...",
errorMessage: "An unexpected error occured, we could not process your request!",
load: null
},
supported: ["fetch", "save", "destroy"],
render: function () {
if (this.options.load)
this.load();
},
load: function (load) {
if (load)
this.options.load = load;
this._reset();
if (_.isFunction(this.options.load)) {
this.$el.html("");
this.options.load.call(this);
return;
}
_(this.options.load.tasks).each(function (models, method) {
if (_.isArray(models))
_(models).each(function (model) {
this._addTask(model, method);
}, this);
else
this._addTask(models, method);
}, this);
this._onRun();
_(this.tasks).each(function (task) {
var model = task.model;
var method = task.method;
var options = {
beforeSend: function (xhr, options) {
this._onRequest(task, xhr);
}.bind(this),
error: function (xhr, statusText, error) {
this._onError(task, xhr);
}.bind(this),
success: function (data, statusText, xhr) {
this._onSync(task, xhr);
}.bind(this)
};
if (model instanceof Backbone.Model) {
if (method == "save")
model[method](null, options);
else
model[method](options);
}
else {
if (method in model)
model[method](options);
else
model.sync(method == "fetch" ? "read" : (method == "save" ? "update" : "delete"), model, options);
}
}, this);
},
_addTask: function (model, method) {
if (!_(this.supported).contains(method))
throw new Error("Method " + method + " is not supported!");
this.tasks.push({
method: method,
model: model
});
},
_onRun: function () {
this.$el.html(this.options.pendingMessage);
if (this.options.load.request)
this.options.load.request.call(this);
},
_onRequest: function (task, xhr) {
task.abort = function () {
xhr.abort();
};
},
_onError: function (task, xhr) {
this._abort();
this.$el.html(this.options.errorMessage);
if (this.options.load.error)
this.options.load.error.call(this);
},
_onSync: function (task, xhr) {
++this.complete;
if (this.complete == this.tasks.length)
this._onEnd();
},
_onEnd: function () {
this.$el.html("");
if (this.options.load.sync)
this.options.load.sync.call(this);
},
_reset: function () {
this._abort();
this.tasks = [];
this.complete = 0;
},
_abort: function () {
_(this.tasks).each(function (task) {
if (task.abort)
task.abort();
});
}
});

Categories

Resources