How can I upload Images in MongoDB and display it in on my Template? - mongodb

How can I store photos in mongodb and display it in my template Dynamically .
I have already created a form which stores the data of the user but I want to fetch the photo and render it through the template . Is there any way to do that ?
MongoDB only showing me C:\fakepath\33783991_259829344578817_7526307875543580672_n.jpg" ! What does that mean ? Is there any working package for meteor file except cloudinary ?

If you don't mind using a package use this one Meteor-Files
It's very easy this is an example below according to the documentation:
Upload form (template):
<template name="uploadForm">
{{#with currentUpload}}
Uploading <b>{{file.name}}</b>:
<span id="progress">{{progress.get}}%</span>
{{else}}
<input id="fileInput" type="file" />
{{/with}}
</template>
Shared code:
import { FilesCollection } from 'meteor/ostrio:files';
const Images = new FilesCollection({collectionName: 'Images'});
export default Images; // To be imported in other files
Client's code:
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();
}
}
});
By default if config.storagePath isn't passed into Constructor it equals to assets/app/uploads and relative to a running script
On development stage: yourDevAppDir/.meteor/local/build/programs/server. Note: All files will be removed as soon as your application rebuilds or you run meteor reset. To keep your storage persistent during development use an absolute path outside of your project folder, e.g. /data directory.
On production: yourProdAppDir/programs/server. Note: If using MeteorUp (MUP), Docker volumes must to be added to mup.json, see MUP usage
Hint:
You may then use the upload by base64 settings in the insert method
and listen on the onuploaded event to save in your database.
To show the image in your template you may code it like so
<img src="data:image/jpeg;base64,{{ImginBase64}}" class="img-responsive">
Read more about Data URI Scheme
Source : Documentation

You should encode your image in base64, in order to save it in a mongodb document.
Beware to not exceed the 16MB BSON format limit (or use Mongodb's GridFS). In the template you can use the base64 string of the image in the src attribute of the img.

It is better to use an Object storage service like GridFS, S3 or Google Cloud storage, and link it with your Mongo document. Alternatively, you can store your images in base64 format inside the Document itself.
https://forums.meteor.com/t/meteor-secure-file-upload-download-with-s3/38197

There are lot of packages that you can use for this.
I recommend CollectionFS .
You need to add this 3 packages and you're all set .
cfs:standard-packages
cfs:gridfs // storage adapter package . You can change this if you want.
cfs:filesystem
Let's start with Inserting Image.
1. Create ImageCollection.js in your lib folder
import { Mongo } from 'meteor/mongo';
export const BOOK = new Mongo.Collection('books');
var imageStore = new FS.Store.GridFS("images");
export const Images = new FS.Collection("images", {
stores: [imageStore]
});Images.deny({
insert: function(){
return false;
},
update: function(){
return false;
},
remove: function(){
return false;
},
download: function(){
return false;
}
});
Images.allow({
insert: function(){
return true;
},
update: function(){
return true;
},
remove: function(){
return true;
},
download: function(){
return true;
}
})
2. Import Images collection in Client and Server side.
For eg,
import {Images} from '../lib/imageCollection';
3. Add Input type "file" in form and according to your Use.
4. Create a change event in .JS file of that template.
'change #bookCover': function (event) {
event.preventDefault();
console.log("changed!")
var files = event.target.files;
for (var i = 0, ln = files.length; i < ln; i++) {
Images.insert(files[i], function (err, fileObj) {
// Inserted new doc with ID fileObj._id, and kicked off the data upload using HTTP
bookImgId=fileObj._id;
});
}
},
Check in Your Database Image will be inserted.
5. To Display Image Add this HTML where you want to see Image.
6. Add This code in Your js file where you are displaying image.
bookImage: function (id) {
// console.log(id);
var imageBook = Images.findOne({_id:id});
// console.log("img: "+imageBook);
var imageUrl = imageBook.url();
return imageUrl; // Where Images is an FS.Collection instance
}
Note : Make sure you're importing your Book collection where you want display Image.

Related

Upload image to firebase storage from React Dropzone (gives invalid Image)

I am using React Dropzone to upload files from React to firebase as shown below:
const onDrop = useCallback((acceptedFiles, fileRejections) => {
//Check if file type is image
//Check if file size < 5MB
//Upload
if (fileRejections.length > 0) {
setError(true);
} else setError(false);
if (acceptedFiles.length > 0) {
const file = acceptedFiles[0];
console.log(file);
setFile({
...file,
preview: URL.createObjectURL(file),
});
setFileUploaded(true);
}
}, []);
and this is my upload handler:
const handleImageUpload = () => {
//Upload Image to Firebase
//Check if file exists
if (file !== null || file !== undefined) {
const storageRef = ref(
Client.storage,
`/db-dev/user-metadata/portfolio/images/first-image.jpg`
);
console.log('Process begins');
uploadBytes(storageRef, file).then((snapshot) => {
console.log('Uploaded a blob or file!');
});
}
};
these two things do the work but I believe for some reason they're not encoding or decoding the image as in firebase storage folder I see image as invalid image.
Can someone help me to understand where things are going wrong? (To make sure file is loaded properly, I am also viewing the file using: preview: URL.createObjectURL(file), and it loads correctly in browser.
For file upload I am following the latest firebase documentation
It sets file type to octet-stream not sure what that means:
Edit 1: I tried to set metadata to image/jpeg:
uploadBytes(storageRef, file, {
contentType: 'image/jpeg',
}).then((snapshot) => {
console.log('Uploaded a blob or file!');
});
But now it shows:
The problem was in this step:
setFile({
...file,
preview: URL.createObjectURL(file),
});
for some reason it wasn't spreading correctly. I changed it to:
setFile({
file:file,
preview: URL.createObjectURL(file),
});
and the upload function to:
const handleImageUpload = () => {
//Upload Image to Firebase
//Check if file exists
if (file !== null || file !== undefined) {
const storageRef = ref(
Client.storage,
`/db-dev/user-metadata/portfolio/images/first-image.jpg`
);
console.log('Process begins');
uploadBytes(storageRef, file.file, {
contentType: file.file.type,
}).then((snapshot) => {
console.log('Uploaded a blob or file!');
});
}
};
and then it worked fine. Although this was a really silly thing on my part but hope this helps someone in future

Express [413 too large] with QuillJS image

I am trying to use QuillJS to let the user write a rich text, and then store it as JSON to display later on. There are 2 of these rich text areas in a single form, and may include images. QuillJS encodes images as base64 strings, and my POST request results in 413 by Express.
I have tried to change the limits by adding express json parameters, even trying extreme numbers.
// app.js
//----------------------------------------------------
// Middlewares
//----------------------------------------------------
app.use(express.json({limit: '2000mb'}));
app.use(express.urlencoded({extended: true, limit:'2000mb'}));
Even this did not help and I think it is not logical to let these parameters with such values.
I tried with json and urlencoded enctypes. When I tried to post with multipart/form, req.body was empty.
// My html page (pugJS)
form(enctype='application/x-www-form-urlencoded', action='/editor/page',
method='POST', onsubmit='return addContent()')
.form-control
label Content-1
div#toolbar
div#editor
input#content(name='content', type='text', hidden)
addContent() function that runs before form submit simply changes input#content's value with JSON.stringify(#editor.getContents())
I want to be able to store two quill content in a single database row, to display later.
A better approach to this would be to overwrite the image upload function and then save the image in Amazon S3 or some cloud server. Then you paste it inside the editor as <img src="http://uploaded-image-url"> This would solve your problem of maximum memory issue.
I fixed my problem few hours before #argo mentioned and I did it that way. So I wanted to post little bit of detail to the solution. I have been also guided by a github issue but can't seem to find the link again, in case I find it I will edit the post and add it.
// Quill - EN content
var quillEn = new Quill('#editor-en', {
modules: {
toolbar: toolbarOptions
},
theme: 'snow'
});
// set custom image handler
quillEn.getModule('toolbar').addHandler('image', () => {
selectLocalImage(quillEn);
});
// create fake input to upload image to quill
function selectLocalImage(editor) {
const input = document.createElement('input');
input.setAttribute('type', 'file');
input.setAttribute('accept', 'image/png, image/jpeg')
input.click();
// Listen upload local image and save to server
input.onchange = () => {
const file = input.files[0];
saveImageToServer(editor, file);
};
}
// upload image to server
function saveImageToServer(editor, file) {
const fd = new FormData();
fd.append('image', file);
const xhr = new XMLHttpRequest();
xhr.open('POST', '/api/page/upload_image', true);
xhr.onload = () => {
if (xhr.status === 200) {
// this is callback data: url
const url = JSON.parse(xhr.responseText).data;
insertToEditor(editor, url);
}
};
xhr.send(fd);
}
// manipulate quill to replace b64 image with uploaded image
function insertToEditor(editor, url) {
// push image url to rich editor.
const range = editor.getSelection();
editor.insertEmbed(range.index, 'image', url.toString());
}
In the backend where you POST image, you must return json as { data: FullUrlToImg } with 200 response, if you want to change your status to 201 or something else, don't forget to update it in saveImageToServer function.
So to summarize, you set custom image handler for your quill editor, you post the image to server as soon as user chooses to insert, then you replace the URL with your uploaded image in the editor.
Thanks.

Using search feature in Ionic framework

I am a UI person and very new to ionic framework.. I wanted to add search feature in my android app built using Ionic framework. After a research i found that I will need to use this plugin https://github.com/djett41/ionic-filter-bar. but there is no detail documentation available. Can anyone please guide how to use this plugin working. I have made all setup but stuck with actual code.
First of all you must install the plugin. You can use bower for that:
bower install ionic-filter-bar --save
and it will copy all the javascript and css needed in the lib folder inside www.
Then you must add the references to the css to your index.html:
<link href="lib/ionic-filter-bar/dist/ionic.filter.bar.css" rel="stylesheet">
same thing for the javascript:
<script src="lib/ionic-filter-bar/dist/ionic.filter.bar.js"></script>
You have to inject the module jett.ionic.filter.bar you your main module:
var app = angular.module('app', [
'ionic',
'jett.ionic.filter.bar'
]);
and you must reference the service $ionicFilterBar in your controller:
angular.module('app')
.controller('home', function($scope, $ionicFilterBar){
});
Now you can start using it.
In my sample I want to trigger the search-box when the user clicks/taps on a icon in the header. I would add this HTML to the view:
<ion-nav-buttons side="secondary">
<button class="button button-icon icon ion-ios-search-strong" ng-click="showFilterBar()">
</button>
</ion-nav-buttons>
The action trigger an event in my controller showFilterBar:
$scope.showFilterBar = function () {
var filterBarInstance = $ionicFilterBar.show({
cancelText: "<i class='ion-ios-close-outline'></i>",
items: $scope.places,
update: function (filteredItems, filterText) {
$scope.places = filteredItems;
}
});
};
which creates the $ionicFilterBar and shows it.
As you can see here I am using an array of objects $scope.places
$scope.places = [{name:'New York'}, {name: 'London'}, {name: 'Milan'}, {name:'Paris'}];
which I have linked to the items member of my $ionicFilterBar. The update method will give me in filteredItems the items (places) filtered.
You can play with this plunker.
Another option is to use the plugin to actually fetch some data remotely through $http.
If we want to achieve this we can use the update function again.
Now we don't need to bind the items to our array of objects cause we won't need the filtered elements.
We will use the filterText to perform some action:
$scope.showFilterBar = function () {
var filterBarInstance = $ionicFilterBar.show({
cancelText: "<i class='ion-ios-close-outline'></i>",
// items: $scope.places,
update: function (filteredItems, filterText) {
if (filterText) {
console.log(filterText);
$scope.fetchPlaces(filterText);
}
}
});
};
We will call another function which will, maybe, call $http and return some data which we can bind to our array of objects:
$scope.fetchPlaces = function(searchText)
{
$scope.places = <result of $http call>;
}
Another plunker here.
PS:
If you want to configure it using some sort of customization you must do it in your configuration using the provider $ionicFilterBarConfigProvider:
angular.module('app')
.config(function($ionicFilterBarConfigProvider){
$ionicFilterBarConfigProvider.clear('ion-ios-close-empty');
})
PPS:
In my plunker I've included the css and the script directly copying it from the source.
UPDATE:
Someone asked not to replace the list with the updated one.
My cheap and dirty solution is to check if the filterText contains some values. If it's empty (no searches) we go throught each element an set a property found = false otherwise we compare the places array we the filteredItems array.
Matching elements will be marked as found.
function allNotFound(filteredItems) {
angular.forEach($scope.places, function(item){
item.found = false;
});
}
function matchingItems(filteredItems) {
angular.forEach($scope.places, function(item){
var found = $filter('filter')(filteredItems, {name: item.name});
if (found && found.length > 0) {
console.log('found', item.name);
item.found = true;
} else {
item.found = false;
console.log('not found', item.name);
}
});
and now we can integrate the filter bar this way:
$scope.showFilterBar = function () {
var filterBarInstance = $ionicFilterBar.show({
cancelText: "<i class='ion-ios-close-outline'></i>",
items: $scope.places,
update: function (filteredItems, filterText) {
if (!filterText) {
allNotFound();
} else {
matchingItems(filteredItems);
}
}
});
};
We can use the found attribute of the object to change the style of the element.
As always, a Plunker to show how it works.
Ionic uses Angular, and Angular include an atributte filter very useful. Look this: https://docs.angularjs.org/api/ng/filter/filter and the example there. Regards

JQueryMobile saving a form to a txt file

I'm building a app with jquerymobile and I've a page which is a form where I have to fill some info about the field job I have done so I can save it, instead of arriving to the store and fill the paperwork by guessing the time of arrival and the time of the finish.
So, I want to fill the form and when I tap on submit, it saves a txt or another file type on the android phone.
Thanks
This worked for me...
When user clicks the save button
var form_1;
var jsonString;
function saveFormState() {
form_1 = $("#form").find("select,textarea, input").serializeArray();
jsonString = JSON.stringify(form_1);
console.log(jsonString);
getFSToSaveForm();
}
function getFSToSaveForm(){
window.requestFileSystem(LocalFileSystem.PERSISTENT,0 ,function(fileSystem){
var entry=fileSystem.root;
entry.getDirectory('myForms', {create:true, exclusive:false}, function(dirEntry){
dirEntry.getFile('formToSave.json', { create: true, exclusive: false}, saveToJsonFile, onError);
}, onError);
}, onError);
}
function saveToJsonFile(fileEntry){
fileEntry.createWriter(function(writer){
writer.onwrite = function (evt) {
console.log("Wrote to file: " + jsonString);
};
writer.write(jsonString);
}, onError);
}
If you want to restore:
+Read the file and save the read text on a vaiable
Then use some Jquery.
var jsonString;
function getFSToRead(){} //You can find the code in the cordova API http://cordova.apache.org/docs/en/2.5.0/cordova_file_file.md.html
function restoreFormState() {
var newObjectArray ;
newObjectArray = JSON.parse(jsonString);
console.log(newObjectArray.length);
jQuery.each( newObjectArray, function( i, field ) {
$( '#' + field.name).val(field.value);
});
}
Hope that helps

Extjs file upload progress

I have seen form file upload example in ExtJS4 and i need customize progress of the file upload.
I see waitMsg config property, but i don't want use that and i don't want use extjs 3rd party plugins.
So, how i can get simply current upload progress from upload form in extjs?
The waitMsg uses a message box with an infinitely auto-updating progress bar. So you can't just create a progressbar that displays the current upload.
You could create your own Ext.ProgressBar and estimate the upload time and when its done you set it to the max value. But I guess you don't want that.
To answer your question: You cannot simply track the current upload progress.
If you really need this user experience you can try a 3rd party component.
To quote the docs:
File uploads are not performed using normal "Ajax" techniques, that is
they are not performed using XMLHttpRequests. Instead the form is
submitted in the standard manner with the DOM element
temporarily modified to have its target set to refer to a dynamically
generated, hidden which is inserted into the document but
removed after the return data has been gathered.
To show real progress you can use onprogress callback of XMLHttpRequest:
Ext.override(Ext.data.request.Ajax, {
openRequest: function (options) {
var xhr = this.callParent(arguments);
if (options.progress) {
xhr.upload.onprogress = options.progress;
}
return xhr;
}
});
Then use like here:
Ext.Ajax.request({
url: '/upload/files',
rawData: data,
headers: { 'Content-Type': null }, //to use content type of FormData
progress: function (e) {
console.log('progress', e.loaded / e.total);
}
});
See online demo here.
buttons: [{
text: 'Upload',
handler: function () {
var form = this.up('form').getForm();
if (form.isValid()) {
form.submit({
url: '/upload/file',
waitMsg: 'Uploading your file...',
success: function (f, a) {
var result = a.result,
data = result.data,
name = data.name,
size = data.size,
message = Ext.String.format('<b>Message:</b> {0}<br>' +
'<b>FileName:</b> {1}<br>' +
'<b>FileSize:</b> {2} bytes',
result.msg, name, size);
Ext.Msg.alert('Success', message);
},
failure: function (f, a) {
Ext.Msg.alert('Failure', a.result.msg);
}
});
}
}
}]
Live demo with progress window is here