I am trying to download a image, which is nothing but a chunk of binary data, using imagelink. For downloading i am using enyo.Ajax module. It is giving back an warning : "Ajax request set to handleAs JSON but data was not in JSON format " .
following is what i have implemented till now.
enyo.kind({
name:"enyo.sample.ajaxapp",
components:[
{kind:"onyx.Input",name:"urlinput", placeholder:"Input URL",classes:"input"},
{kind:"onyx.Button",name:"download",ontap:"fetch",classes:"button",content:"Fetch"},
{kind:"enyo.Control",name:"image",tag:"img",classes:"image"}
],
fetch:function(inSender,inEvent){
var ajax= new enyo.Ajax({
url:this.$.urlinput.getValue(),
handleAs:'blob'
});
ajax.go();
ajax.responseType='blob';
ajax.response(this,"processResponse");
ajax.error(this,"errorResponse");
},
processResponse:function(inSender,inResponse){
var img=this.$.image;
var blob=inResponse;
//var data=window.URL.createObjectURL(blob);
img.setSrc(blob);
},
errorResponse:function(inSender,inResponse){
console.log("error occured");
}
});
I wants to know whether is it not possible to get data apart from json/text/xml? If not, then how can i modify my code to get it downloaded. By default all the data received as JSON, so i am setting handleAs to bolb while creating ajax object. Do i need to change contentType or something else.
I don't think Ajax is the best way to request image data. You have (at least) two solutions:
Set the src attribute on an <img> tag and use onload to know
when the resource was downloaded.
Base 64 encode the image from the
server and set the src as the encoded data plus the appropriate
header info.
See this question for more details: Asynchronously load images with jQuery
Related
I have a Meteor app and I am interested in getting image upload to work in the simplest possible manner.
The simplest manner I can come up with is to somehow convert the image to a base64 string on the client and the save it to the database as a string.
How is it possible to convert an image on the users filesystem to a base64 string and then save it to the database?
You can use an HTML5 file input :
HTML
<template name="fileUpload">
<form>
<input type="file" name="imageFile">
<button type="submit" disabled={{submitDisabled}}>
Submit
</button>
</form>
</template>
Then listen to the change event and use a FileReader to read the local file as a base64 data url that we're going to store in a reactive var :
Template.fileUpload.created=function(){
this.dataUrl=new ReactiveVar();
};
Template.fileUpload.events({
"change input[type='file']":function(event,template){
var files=event.target.files;
if(files.length===0){
return;
}
var file=files[0];
//
var fileReader=new FileReader();
fileReader.onload=function(event){
var dataUrl=event.target.result;
template.dataUrl.set(dataUrl);
});
fileReader.readAsDataURL(file);
}
});
Then we can use the reactive var value to allow/disallow form submission and send the value to the server :
Template.fileUpload.helpers({
submitDisabled:function(){
return Template.instance().dataUrl.get();
}
});
Template.fileUpload.events({
"submit":function(event,template){
event.preventDefault();
//
Meteor.call("uploadImage",template.dataUrl.get());
}
});
You will need to define a server method that saves the dataUrl to some collection field value, what's cool about dataUrls is that you can use them directly as an image tag src.
Note that this solution is highly unscalable as the image data won't be cachable and will pollute the app database regular communications (which should only contain text-like values).
You could fetch the base64 data from the dataUrl and upload it to Google Cloud Storage or Amazon S3 and serve the files behind a CDN.
You could also use services that do all of this stuff for you like uploadcare or filepicker.
EDIT :
This solution is easy to implement but comes with the main drawback that fetching large base64 strings from mongodb will slow your app from fetching other data, DDP communications are always live and not cachable at the moment so your app will always redownload image data from the server.
You wouldn't save dataUrls to Amazon, you would save the image directly, and it would be fetched by your app using an Amazon URL with a cachable HTTP request.
You have two choices when it comes to file upload : you can upload them directly from the client using specific javascript browser APIs or you can upload them within Node.js (NPM modules) APIs in the server.
In the case you want to upload from the server (which is usually simpler because you don't need to require that the users of your apps authenticate against third party services, only your server will act as a trusted client to communicate with Amazon API), then you can send the data that a user want to upload through a method call with a dataUrl as argument.
If you don't want to dive into all this stuff consider using uploadcare or filepicker, but keep in mind that these are paid services (as is Amazon S3 BTW).
Not sure if this is the best way, but you can easily do this with a file reader. In the Template event handler where you get the file contents, you can pass the file to the reader and get back a base64 string. For example, something like this:
Template.example.events({
'submit form': function (event, template) {
var reader = new FileReader();
var file = template.find('#fileUpload').files[0]; // get the file
reader.onload = function (event) {
// event.target.result is the base64 string
}
reader.readAsDataURL(file);
}
});
I'm trying to work with the IUCN Red List web services API (here's an example output). Unfortunately I haven't been able to find any documentation other than this one-off Gist. It looks as though the API is constructing an HTML document rather than returning a data object, which isn't something I've experienced in the past. I also notice that in the example there is no mention of a ?callback=JSON_CALLBACK in the URL, which I would expect when dealing with JSONP.
I've constructed an http request in AngularJS like so:
atRiskApp.controller('IucnController', ['$scope', '$routeParams', '$http', function ($scope, $routeParams, $http) {
$scope.iucn = $routeParams.iucn; // pulling a number from the URL: ex. 22718591
$scope.getIUCN = function () {
var iucnUrl = 'http://api.iucnredlist.org/details/' + $scope.iucn + '/0.js';
$http.jsonp( url )
.success( function (response) {
console.log(response);
})
.error( function (response) {
console.log(response);
});
};
}]);
Although the HTML document is being successfully passed to my app I'm getting the following error message:
Uncaught SyntaxError: Unexpected token <
It seems like the app is expecting to get Javascript, and is instead getting an HTML document, which it apparently can't parse. I've tried adding a config object to the request based on the angular docs: $http.jsonp( {url: iucnUrl, responseType: 'text'} ) without any luck.
My question is, how do I work with the returned HTML document, or am I way off track here?
Response from the API is an HTML document with a javascript extension:
On the page you linked to in your comment , I found some potentially useful information under the heading API Index.
You can actually get JSON for all levels of taxonomy, including your example Aneides aeneus. However, this JSON doesn't include all of the data from the HTML version, so it's not as useful. Hopefully this helps a little.
API Index (excerpt)
It is also possible to retrieve the row(s) of the index corresponding to an individual species:
http://iucn-redlist-api.heroku.com/index/species/panthera-leo.json
You can use dashes for spaces, as a convenient replacement for the standard URL escape, %20.
The HTML format contains direct links to the species account pages. The CSV and JSON formats include a species_id column which can be used to construct species account URLs as follows:
http://iucn-redlist-api.heroku.com/details/species_id/0
To use the index JSON in Web pages directly, you may need JSONP padding; use the “.js” extension and add a “callback” parameter with the name of the function to use.
http://iucn-redlist-api.heroku.com/index/genus/Dioscorea.js?callback=show
I diagonally looked over the website and its sitemap and found no reference to a public API. All the output is HTML, and it makes sense that json parse method jsonp will not be able to make sense of it. First < it encounters, it will fail (as is apparent).
First of all, I would contact the site admin to simply ask if there is an API that will yield you XML or json or some other object notation that's convenient to work with.
Then there's the scenario where his or her answer would be 'no':
Parsing HTML is not something to be taken lightly and certainly not something you would write yourself unless absolutely necessary.
Luckily, there are ways to get data from html using jQuery.parseHTML(), pure ('vanilla') javascript ways you can use from within AngularJS and full-blown HTML parsing libraries such as HTML Agility Pack(for use in .NET), all of which can get you to the heart of the data within the DOM nodes you're trying to poke at.
There are many other libraries that might serve you better, but these examples will give you a good starting point to canvas the landscape of HTML parsing. This will take some looking into, but it will be more than worth it.
I am new to Django but i am advanced programmer in other frameworks.
What i intend to do:
Press a form button, triggering Javascript that fires a Ajax request which is processed by a Django View (creates a file) that return plain simple JSON data (the name of the file) - and that is appended as a link to a DOM-Element named 'downloads'.
What i achieved so far instead:
Press the button, triggering js that fires a ajax request which is process by a Django view (creates a file) that return the whole page appended as a duplicate to the DOM-Element named 'downloads' (instead of simple JSON data).
here is the extracted code from the corresponding Django view:
context = {
'filename': filename
}
data['filename'] = render_to_string(current_app+'/json_download_link.html', context)
return HttpResponse(json.dumps(data), content_type="application/json")
I tried several variants (like https://stackoverflow.com/a/2428119/850547), with and without RequestContext object; different rendering strats.. i am out of ideas now..
It seems to me that there is NO possibility to make ajax requests without using a template in the response.. :-/ (but i hope i am wrong)
But even then: Why is Django return the main template (with full DOM) that i have NOT passed to the context...
I just want JSON data - not more!
I hope my problem is understandable... if you need more informations let me know and i will add them.
EDIT:
for the upcoming questions - json_download_link.html looks like this:
Download
But i don't even want to use that!
corresponding jquery:
$.post(url, form_data)
.done(function(result){
$('#downloads').append(' Download CSV')
})
I don't understand your question. Of course you can make an Ajax request without using a template. If you don't want to use a template, don't use a template. If you just want to return JSON, then do that.
Without having any details of what's going wrong, I would imagine that your Ajax request is not hitting the view you think it is, but is going to the original full-page view. Try adding some logging in the view to see what's going on.
There is no need to return the full template. You can return parts of template and render/append them at the frontend.
A template can be as small as you want. For example this is a template:
name.html
<p>My name is {{name}}</p>
You can return only this template with json.dumps() and append it on the front end.
What is your json_download_link.html?
assuming example.csv is string
data ={}
data['filename'] = u'example.csv'
return HttpResponse(simplejson.dumps(data), content_type="application/json")
Is this what you are looking for?
I have code that does POST attachments to Couch docs using jquery.form.js. That's all good, but I really need to allow the user to enter multiple files in the form, let's say 5 files for now, then in code iterate the five files in the form, creating one new Couch doc and attachment for each file. This is veeeery difficult if not impossible using only jQuery. It could be done using Couch "inline attachments" but then you would need a server-side (PHP probably) script to Base64 encode the binary image data. This really isn't an option for me because this is a Couchapp.
So the following code doesn't work, it generates an "invocation" error in jQuery. My assumption is that you can't simply add the reference to a binary file in the data attrib...
var url= _.couchUrl() + me.photoArgs.db +"/" +
couchDoc._id + "/attachment?rev=" + couchDoc._rev;
$.ajax({
type: "PUT",
url: url,
headers: {
"Content-Length": file.size,
"Content-Type": file.type
},
data: file,
success: function (response) {
console.log("Attachment was uploaded");
me.fileCnt--;
if (me.fileCnt == 0) console.log("Attachment(s) uploaded");
},
error: function (response) {
_.flashError('Attachment ajaxSubmit failed',me,response);
}
});
The code is clipped from inside a larger function. I've logged the url and the file, they both have correct data so they're not the issue.
Does anyone think the above should work? If so, what am I doing wrong?
Thanks a lot for your advice :-)
You have two options there:
Use inline attachments. You don't have to use PHP to decode base64 data: just add to your CouchApp /_utils/script/base64.js file (yes, it ships with CouchDB Futon) as CommonJS module and you'll be fine.
Use Multipart API (scroll a bit down for an example). I haven't much experience with jQuery to quick make a working prototype, but this question you may found helpful.
Update: found good working example how to upload multiple binary attachments to CouchDB using multipart API.
Google Voice has XML URLs so I was wondering how somebody would pull the JSON part from the returned XML and parse it out to a page. Google Voice's search capability is busted right now and I want to get access to my history. I'm thinking that a synchronous call to all of the pages up to the last known page number in my history should do it...
This may be your best bet...
Read about dataType conversion here: http://api.jquery.com/extending-ajax/
Particularly the section that says:
You can define converters "inline," inside the options of an ajax call. For example, the following code requests an XML document, then extracts relevant text from it, and parses it as "mydatatype":
$.ajax( url, {
dataType: "xml text mydatatype",
converters: {
"xml text": function( xmlValue ) {
// Extract relevant text from the xml document
return textValue;
}
}
});
I don't know if this exact code snippet will return the JSON content properly, but at the very least it should strip it out of the XML response (you may need to add additional code to parse the returned "textValue" as JSON. Perhaps using the jQuery parseJSON method.
Maybe try:
$.ajax( url, {
dataType: "xml text mydatatype",
converters: {
"xml text": $.parseJSON;
}
}
});
Hope this helps.
XML and JSON are not the same data types. You will likely have to process the data as XML, if that's the only type your data is returned as. If the URL has .xml, you might try changing it to .json to see if it returns a JSON data type.
If you give us more information (examples, URLs, etc), someone might be able to help you better.