Is it is possible to send image through meteor call to the API?
Client js
var r = {image : image};
Meteor.apply('callToServer', r, function(error, result){
console.log(result);
});
Server js
Meteor.methods({
uploadAndSaveToDB: function(data){
var result = Meteor.http.post(apiUrl, {
params: { image : data['image']}
});
var result = JSON.parse(result.content);
return result;
},
});
If your question is about how to get the image data and send it to your api, it depends on a couple factors:
How are you getting the image's data in the first place from your app (a submission form, a URL, some drawing library...)
In what format does the API you are calling expects the image data to be sent (URL, raw data, encrypted...)
If you are simply asking if it is doable, then yes, definitely. You will just need to add the http package for this:
meteor add http
You can then make requests to your api pretty much like you wrote it. Just make sure to give the right name to your method call (also use call and not apply if you are not submitting an array of arguments):
Client js
var r = {image : image};
Meteor.call('uploadAndSaveToDB', r, function(error, result){
console.log(result);
});
Server js
Meteor.methods({
uploadAndSaveToDB: function(data){
var result = HTTP.post(apiUrl, {
params: { image : data['image']}
});
var result = JSON.parse(result.content);
return result;
},
});
Related
I was in the middle of teaching myself some Ajax, and this lesson required building a simple file upload form locally. I'm running XAMPP on windows 7, with a virtual host set up for http://test. The solution in the book was to use node and an almost unknown package called "multipart" which was supposed to parse the form data but was crapping out on me.
I looked for the best package for the job, and that seems to be formidable. It does the trick and my file will upload locally and I get all the details back through Ajax. BUT, it won't play nice with the simple JS code from the book which was to display the upload progress in a progress element. SO, I looked around and people suggested using socket.io to emit the progress info back to the client page.
I've managed to get formidable working locally, and I've managed to get socket.io working with some basic tutorials. Now, I can't for the life of me get them to work together. I can't even get a simple console log message to be sent back to my page from socket.io while formidable does its thing.
First, here is the file upload form by itself. The script inside the upload.html page:
document.getElementById("submit").onclick = handleButtonPress;
var httpRequest;
function handleResponse() {
if (httpRequest.readyState == 4 && httpRequest.status == 200) {
document.getElementById("results").innerHTML = httpRequest.responseText;
}
}
function handleButtonPress(e) {
e.preventDefault();
var form = document.getElementById("myform");
var formData = new FormData(form);
httpRequest = new XMLHttpRequest();
httpRequest.onreadystatechange = handleResponse;
httpRequest.open("POST", form.action);
httpRequest.send(formData);
}
And here's the corresponding node script (the important part being form.on('progress')
var http = require('http'),
util = require('util'),
formidable = require('formidable');
http.createServer(function(req, res) {
if (req.url == '/upload' && req.method.toLowerCase() == 'post') {
var form = new formidable.IncomingForm(),
files = [],
fields = [];
form.uploadDir = './files/';
form.keepExtensions = true;
form
.on('progress', function(bytesReceived, bytesExpected) {
console.log('Progress so far: '+(bytesReceived / bytesExpected * 100).toFixed(0)+"%");
})
.on('file', function(name, file) {
files.push([name, file]);
})
.on('error', function(err) {
console.log('ERROR!');
res.end();
})
.on('end', function() {
console.log('-> upload done');
res.writeHead(200, "OK", {
"Content-Type": "text/html", "Access-Control-Allow-Origin": "http://test"
});
res.end('received files: '+util.inspect(files));
});
form.parse(req);
} else {
res.writeHead(404, {'content-type': 'text/plain'});
res.end('404');
}
return;
}).listen(8080);
console.log('listening');
Ok, so that all works as expected. Now here's the simplest socket.io script which I'm hoping to infuse into the previous two to emit the progress info back to my page. Here's the client-side code:
var socket = io.connect('http://test:8080');
socket.on('news', function(data){
console.log('server sent news:', data);
});
And here's the server-side node script:
var http = require('http'),
fs = require('fs');
var server = http.createServer(function(req, res) {
fs.createReadStream('./socket.html').pipe(res);
});
var io = require('socket.io').listen(server);
io.sockets.on('connection', function(socket) {
socket.emit('news', {hello: "world"});
});
server.listen(8080);
So this works fine by itself, but my problem comes when I try to place the socket.io code inside my form.... I've tried placing it anywhere it might remotely make sense, i've tried the asynchronous mode of fs.readFile too, but it just wont send anything back to the client - meanwhile the file upload portion still works fine. Do I need to establish some sort of handshake between the two packages? Help me out here. I'm a front-end guy so I'm not too familiar with this back-end stuff. I'll put this aside for now and move onto other lessons.
Maybe you can create a room for one single client and then broadcast the percentage to this room.
I explained it here: How to connect formidable file upload to socket.io in Node.js
I'm having difficulty accessing requestJSON on a jQuery $.ajax object outside of the success callback. If I do:
var ajax_request = $.ajax({
dataType: 'json',
contentType: 'application/json'
});
console.log(ajax_request.responseJSON);
// this results in `undefined`
How can I access the responseJSON without adding a .success() callback? If I inspect ajax_request in Firebug, I can see the responseJSON property, and the data I expect, but I can't access it via:
ajax_request.responseJSON
More specifically, I'm building an SPA using Sammy and Knockout. In some routes, I need to be able to get JSON from cache, and if it doesn't exist, get the value from a service call and then set it into cache:
var cached_json = storage.fetch('cached_json', function() {
// make service call
return $.getJSON(url);
});
event_context.render('template.tpl', {'json': cached_json}).appendTo('#my-target');
But, of course, calling storage.fetch doesn't cause the rest of the code to pause until $.getJSON is complete. This is the part I can't quite figure out how to structure.
here's how i would implement it
responseJSON = "";
$.get("myurl.php",function(jdata){
responseJSON = jdata;
},"json");
i like to see the ajax method at a glace, but in your case you can do the same by
....
success : function(jdata){ responseJSON = jdata; }
....
PS: i believe that initializing the blank responseJSON is not required since any variable without var is in global scope, but it would help for clarity
I ended up solving this by creating a deferred object that gets or creates the value I need:
function get_or_create_cache(storage, key, service_endpoint) {
return $.Deferred(function(deferred) {
var c = storage.get(key);
if (c === null || c === undefined) {
$.when(jsonp_service_request(service_endpoint)).done(function(json) {
storage.set(key, json);
deferred.resolve(json);
});
}
else {
deferred.resolve(c);
}
}).promise();
}
In this function, storage refers to a Sammy.Storage instance. jsonp_service_request is a local function that returns a jsonp response, taking into account the location.hostname for local development, where I'm pointing to local.json files, or a remote environment, where I'm calling into an actual API. jsonp_service_request returns an $.ajax function.
Then in my Sammy route, I can do:
this.get('#/', function(event_context) {
$.when(get_or_create_cache(storage, 'my-cache-key', 'service-endpoint'))
.then(function(json) {
event_context.render('my-template.template', {'value-name': json})
.appendTo('#my-target');
});
});
I am using jQuery on the front to make an AJAX post request using $.post(). I also pass a success function which will do something with the data returned. On my node.js server, I am using express to handle requests, the post request calls another function passing a callback which in the callback does a res.send(). How can I get the request not to finish until the callback is done?
My client-side code is:
$.post("/newgroup/", {name: newgroupname}, function(data) {
console.log(data); // Returns undefined because requests ends before res.send
});
My server-side code is:
app.post('/newgroup/', function(req, res){
insertDocument({name:req.body.name, photos:[]}, db.groups, function(doc){
res.send(doc);
});
});
The insertDocument function is:
function insertDocument(doc, targetCollection, callback) {
var cursor = targetCollection.find( {}, {_id: 1}).sort({_id: -1}).limit(1);
cursor.toArray(function(err, docs){
if (docs == false){
var seq = 1;
}
else {
var seq = docs[0]._id + 1;
}
doc._id = seq;
targetCollection.insert(doc);
callback(doc);
});
}
If the code you've shown us is the real code then the only possibility is that the thing you are returning doc is actually undefined. The callback on the client will not fire before res.send() is triggered.
Are you sure that the callback in insertDocument is exactly as you think? Often callbacks are of the form function(err,doc), i.e. try this:
app.post('/newgroup/', function(req, res){
insertDocument({name:req.body.name, photos:[]}, db.groups, function(err, doc){
res.send(doc);
});
});
Okay I found the answer, I am not sure why this works, I just had to change the name of the variable I was sending to the callback, I assume this is because it had the same name as a parameter, so I changed my insertDocument function to look like this
function insertDocument(doc, targetCollection, callback) {
var cursor = targetCollection.find( {}, {_id: 1}).sort({_id: -1}).limit(1);
cursor.toArray(function(err, docs){
if (docs == false){
var seq = 1;
}
else {
var seq = docs[0]._id + 1;
}
doc._id = seq;
targetCollection.insert(doc);
var new_document = doc;
callback(new_document);
});
}
Could it be a sync/async issue? I don't know what library you are using for your saves, but is it a case were the call should be something more like this?
targetCollection.insert(doc, function(err, saveddoc) {
if (err) console.log(err);
callback(saveddoc);
});
Our team has developed a JS HTML5 canvas based paint application. In the following code, the image data is fetched from the canvas as base 64 encoding and posted to a servlet via ajax. The data post behaves erratically. If the image is simple , as in a straight line, I get Ajax status = 200 and the image gets saved. If the image is complex, then I get a status = 400 and the data is not saved.
Why should the content of the POST create issues with posting of the data itself?
function getCode(){
var canvas = document.getElementById('imageView');
var context = canvas.getContext('2d');
// draw cloud
context.beginPath();
// save canvas image as data url
var dataURL = canvas.toDataURL();
// set canvasImg image src to dataURL
// so it can be saved as an image
document.getElementById('canvasImg').src = dataURL;
var uri= document.getElementById('canvasImg').src;
uri = uri.replace('data:image/png;base64,','');
uri = uri.replace('=', '');
uri = uri.trim();
alert("uri is "+uri);
var ajaxobject ;
if(window.XMLHttpRequest){
ajaxobject = new XMLHttpRequest();
} else if(window.ActiveXObject){
ajaxobject = new ActiveXObject("Microsoft.XMLHTTP");
}else if(window.ActiveXObject){
ajaxobject = new ActiveXObject("Msxml2.XMLHTTP");
}
ajaxobject.open("POST", "SaveImageServlet?image="+uri, true);
ajaxobject.setRequestHeader("Content-type","application/x-www-form-urlencoded");
ajaxobject.onreadystatechange = function(){
if(ajaxobject.readyState==4){
alert(ajaxobject.status);
if(ajaxobject.status==200){
alert(ajaxobject.responseText);
}}
};
ajaxobject.send(null);
}
From looking at your code, the problem seems that you're passing the data in querystring instead of using the request body (as you should be doing since you're setting the POST verb).
Your uri should look like this:
SaveImageServlet
without the question mark and the parameter. The parameter should be set in the request body. Using jquery ajax your request would look like this:
$.ajax({
contentType: 'text/plain',
data: {
"image": yourBase64string
},
dataType: 'application/json', // or whatever return dataType you want
success: function(data){
// callback in case of success
},
error: function(){
// callback in case of error
},
type: 'POST',
url: '/SaveImageServlet'
});
On server side you should be reading the data from the appropriate place. For example, if you're using .Net read it like this:
Request.Form["image"]
instead of:
Request.Querystring["image"]
This should work as intended and consistently.
#Matteo, Thanks for your help and effort. However, AJAX issue never got solved. I found a way to send the base64 image data to the servlet. Just appended it to a hidden field and sent it as a regular form field.
I want to send the filepath of a file on my server to the client in order to play it using a media player. How can I retrieve that string on the client side in order to concatenate it in the src attribute of a <video element without using sockets?
Server snippet:
res.set('content-type', 'text/plain');
res.send('/files/download.mp4');
This is how you make a request to the server without any frameworks. "/path_to_page" is the route you set to the page that is supposed to process the request.
var xhr = new XMLHttpRequest();
xhr.open('GET', '/path_to_page', true);
xhr.onload = function(e) {
if (this.status == 200) {
console.log(this.responseText); // output will be "/files/download.mp4"
}
};
xhr.send();
}
You might also want to send some params.
var formdata = new FormData();
formdata.append("param_name", "value");
So you might for instance want to send the filename or such.
You just need to change 2 lines from the first code snippet. One would be
xhr.open('POST', '/path_to_page', true); // set to post to send the params
xhr.send(formdata); // send the params
To get the params on the server, if you are using express, they are in req.body.param_name
Which framework are you using??
You can declare base path of your project directory in ajax and the followed by your file.
jQuery.ajax({
type: "GET",
url: "/files/download.mp4",
});
Since you are using express (on node), you could use socket.io:
Server:
var io = require('socket.io').listen(80),
fs = require('fs');
io.sockets.on('connection', function (socket) {
socket.on('download', function(req) {
fs.readFile(req.path, function (err, data) {
if (err) throw err;
socket.emit('video', { video: data });
});
});
});
Client:
<script src="/socket.io/socket.io.js"></script>
<script>
var socket = io.connect('http://localhost');
...
// request a download
socket.emit('download', { path: '/files/download.mp4' });
// receive a download
socket.on('video', function (data) {
// do sth with data.video;
});
...
</script>
Edit: didnt notice you didnt want to use sockets. Still it is a viable solution.