Using JSONP when returning XML - javascript

I asked an earlier question which was definitely helpful and let me know about JSONP. However, I see that I have to specify JSONP as the datatype. Now, as far as I know, that is the return type of the data coming back, which would be XML. Can XML be returned using JSONP or am I limited to it coming back as JSONP format? Thanks!

You're limited to JSONP (and not XML) because of how it works. JSONP turns into this:
<script src="myPage?callback=myFunction" type="text/javscript">
So when you take the content, it's effectively doing this:
<script type="text/javascript">
myFunction({ data: value, data2: value2 });
</script>
What comes back is actual running JavaScript, so it can't be XML, you'll get all sorts of syntax errors, exactly as you would doing this:
<script type="text/javascript">
<elem>
<data>value</data>
<data2>value2</data2>
</elem>
</script>
As you can imagine, the JavaScript parser isn't going to like that very much, and doesn't know what to do with it. jQuery can parse XML in most cases without any trouble, but if you're using JSONP and it's for cross-domain requests...well JSONP is your only option there, unless you wrote a proxy page on your site that didn't violate same-origin policy rules, and used it as a proxy to fetch the XML through.

The idea is to send back executable code from the server. Write a jQuery plugin or extend the ajax function to return the XML string as a function parameter.
myCallback("
<root>
<person>
<first>John</first>
<last>Doe</last>
</person>
</root>")
The plugin will parse this string to XML and return it back to your actual callback. As far as your callback is concerned, it is unaware of the string -> xml conversion process.
Here's an existing implementation.
The most ideal interface to this with jQuery would be,
$.ajax({
url: 'http://example.com/resource?type=xml',
dataType: 'xmlp',
success: function(xml) { .. }
});
but since messing around and rewriting jQuery.ajax is problematic, you could write this as a separate namespaced plugin itself which will use getScript underneath.
$.myNamespace.ajax({
..
});
For this to work, you would need control of the server. The server has to know that XML is requested, and respond with a function call which contains the XML string as a parameter. Assuming the callback name you sent over to the remote server was foo, the server will have to respond with something like:
foo("<names><name>..</name></names>")
I think if you were using a browser that supported E4X, then there would be no need to wrap the XML inside a string. The server could simply return the XML as an argument to the callback function:
foo(
<names>
<name>John Doe</name>
</names>
)
But unfortunately, E4X is not widely supported yet.

You can write XML in Javascript function inside in /* comment */ and convert this function to text with method functionname.toString() and parsing text between "/*" and "*/" with JSONP's callback function, that works in all old browsers. Example xml_via_jsonp.js :
function myfunc()
{/*
<xml>
<div class="container">
<div class="panel panel-info col-lg-10 col-lg-offset-1 added-panel">
<div class="panel-heading">Random1 - Random2</div>
<div class="panel-body">
<div>Random3</div>
</div>
</div>
</div>
</xml>
*/}
function callback(func)
{
var myhtml = func.toString();
var htmlstart = myhtml.indexOf('/*');
var htmlend = myhtml.lastIndexOf('*/');
return myhtml.substr(htmlstart+2, htmlend-htmlstart-2);
}

Related

Correct parsing of JSON

First of all, forgive me if any of this code is bad, inefficient, or completely wrong, I haven't worked with JSON at all before, or any sort of API work.
So, I'm just trying to create a basic webpage which will display some information from the JSON obtained through JSONP (did I implement it correctly...?). I thought that I was accessing the id element correctly but it seems not as I've tried getting it to show up with alert, console.log, and setting the inner html of the paragraph. Here is the code:
HTML
</head>
<body>
<p id="main">
test
</p>
</body>
<script src="js/parseJSON.js"></script>
<script type="application/json" src="https://www.aviationweather.gov/gis/scripts/MetarJSON.php?taf=true&bbox=-86,41,-82,45&callback=parseJSON"></script>
</html>
Javascript
var parseJSON = function(json) {
var obj = JSON.parse(json);
console.log(obj.features[0].properties.id);
}
This seems like something simple I'm just screwing up. Any help would be appreciated, thanks!
I'm just trying to create a basic webpage which will display some information from the JSON obtained through JSONP (did I implement it correctly...?).
You said type="application/json" so the browser ignored it because it doesn't know how to execute scripts written in JSON.
JSONP is not JSON, it is JavaScript, so the correct Content Type is application/javascript.
Further https://www.aviationweather.gov/gis/scripts/MetarJSON.php?taf=true&bbox=-86,41,-82,45&callback=parseJSON returns JSON not JSONP.
var parseJSON = function(json) {
var obj = JSON.parse(json);
While it is possible for a JSONP service to provide data in the form of a JavaScript string containing JSON, that is never something I've seen. The argument should not be parsed as JSON. It should be a regular JavaScript data structure.
… but first you need the service to return JSONP.

AJAX modifying the DOM & calling a function

I am on Linux -both browser side & server side- with a recent Firefox 38 or 42 if that matters; this question gives more context, and the github GPLv3 project containing my code. It is not a usual Web application (it would have usually one, and perhaps a dozen, of simultaneous Web users). I am writing or generating both server & browser side code
Let's suppose I have some HTML5 code like
<div id="mydyndiv_id"></div>
I am making an AJAX request with JQuery. On success it should insert some (AJAX generated) HTML element, e.g. <b>bold</b> (in reality it is a much bigger HTML fragment with nested <span>-s whose content is dynamically generated from the POST argument of the AJAX request), into that div and call some other Javascript function doit, e.g. doit(42) only once just after the AJAX request (e.g. that function would clear some other <textarea> in my page, and the 42 argument is provided by the AJAX response). I can change code both on server side (e.g. alter the AJAX processing) and on browser side.
What is the most idiomatic way to achieve that?
making a JSON AJAX which contains both the inserted HTML & the function argument, so the AJAX response could be {"text":"<b>bold</b>", "data": 42}" of Content-type: "application/json" and the Javascript code would be
$.ajax
({url: "/someajax",
method: "POST",
data: {"somearg": "foo"},
datatype: "json",
success: function(jsa) {
$("#mydyndiv_id").html(jsa.text);
doit(jsa.data);
}});
this is rather heavy, the server should double-encode HTML&JSON the HTML fragment: it needs first to construct the <b>bold</b> fragment -with HTML encoding, and then to construct the JSON object and send it.
making an HTML AJAX which has some <script> element. The AJAX response would be of Content-type: text/html and would contain <b>bold</b><script>doit(42)</script>, and the Javascript code would be
$.ajax
({url: "/someajax",
method: "POST",
data: {"somearg": "foo"},
datatype: "html",
success: function(ht) {
$("#mydyndiv_id").html(ht);
}});
this might be wrong, since the doit(42) function could be perhaps called more than once and is kept in the DOM and I don't want that
making a Javascript AJAX; the AJAX response would be of Content-type: application-javascript and would contain:
$("#mydyndiv_id").html("<b>bold</b>");
doit(42);
with the AJAX invocation in Javascript being
$.ajax
({url: "/someajax",
method: "POST",
data: {"somearg": "foo"},
datatype: "script",
success: function(jscode) { /* empty body */ }
})
This is brittle w.r.t. errors in doit(42) (see this question; the only debugging technique I found is lots of console.log and that is painful) and also requires double encoding on server side.
Of course, any other technique is welcome!
PS. If you are curious, the code is commit a6f1dd7514e5 of the MELT monitor (alpha stage) and you would try the http://localhost.localdomain:8086/nanoedit.html URL in your browser; this software (which is also a specialized HTTP server!) would have only very few simultaneous Web users (usually one, perhaps a dozen); in that sense it is not a usual web application. In my dreams it could become a workbench for a small team of (C & C++) software developers, and the GUI of that workbench would be their browser.
These different approaches have pros and cons, but generally the first two options are more advisable, let's see:
JSON AJAX
First of all, working with templating on your server is the right approach. If you use this method you will be able to pass more flexible data from your server to your client as you can e.g. use {"text":"<b>bold</b>", "data": 42, "more_data": 43}".
You are not bound to use just the data at the moment you initially create the service but expand passed data easily.
HTML AJAX
This method is simple and if you would like to have a service for every single piece of data you need to pass, rather than a service for multiple pieces, this is the preferable choice. In difference to the JSON AJAX method, you will not be able to expand here and if needed, you'll naturally have to create a new service for passing new data.
Javascript AJAX
Altough it is possible, tis method is rather unadivsable, as you can not maintain your application in a reasonable way, as your templating is client-side. See what Peter-Paul Koch says here:
Although templating is the correct solution, doing it in the browser is fundamentally wrong. The cost of application maintenance should not be offloaded onto all their users’s browsers (we’re talking millions of hits per month here) — especially not the mobile ones. This job belongs on the server.
Further reading : Why client-side templating is wrong.
First approach looks good for me, but generally it's a little bit ugly to transfer raw HTML via AJAX, if you have to transfer raw HTML it's better to use techniques called PJAX, see jquery-pjax plugin for more information of how to use and customize it.
From my point of view best approach would start using jquery-template to avoid transferring HTML over AJAX and start transfer only object witch would be rendered to template on frontend.Call doit method within handling success is ok until it use data provided in response.
I would rather go with a variation of first approach. But, it depends on the kind of generated HTML that you are currently returning from the server-side.
If it is a simple element, then you could just return a JSON object from server with one of the properties identifying the element.
For example, the response from the web-service would be like:
{'elem': 'b', 'text': 'bold', 'value': '42'}
And you consume that in the AJAX call like this:
$.ajax({
datatype: "json",
...
success: function(response) {
// create the required element client-side
var elem = document.createElement(response.elem);
// use other properties of the response object
elem.textContent = response.text + doit(response.value);
// add the element to your div
$('#mydiv-1')[0].appendChild(elem);
}
});
Where doit is the Javascript function that is already part of your client-side code-base and you just use the arguments returned by the web-service.
Alternatively, if your generated HTML is a complex fragment, then you need to identify common patterns and use client-side templates to transform the returned data into presentation.
For example, your client-side template may look like this:
<script type='text/template' id='tmpl'>
<div><h3></h3><p></p><h5></h5></div>
</script>
Your web-service returns something like this:
{'title': 'title', 'text': 'paragraph', 'value': '42'}
And you consume that in the AJAX call like this:
$.ajax({
datatype: "json",
...
success: function(response) {
// clone the client-side template
var template = $('#tmpl').html(), $elem = $(template);
// append to your div
$('#mydiv-2').append($elem);
// populate the cloned template with returned object properties
$elem.find('h3').text(response.title);
$elem.find('p').text(response.text);
$elem.find('h5').text(doit(response.value));
}
});
This way you avoid returning generated HTML from your server and manage the presentation details at the client-side only. Your web-service needs not to know the presentational aspects and deals only with raw data (consuming or spewing). The client-side code gets data from the web-service and deals with using and/or presenting that data as part of the client-side app.
Demo for both the variations: https://jsfiddle.net/abhitalks/wuhnuv99/
Bottom-line: Don't transfer code. Transfer data. Code should then use that data.

Different types of methods to read JSON

I want to load JSON when the page is loading. I found two methods but what is the difference between following two methods to read JSON.
<script type="text/javascript" src="assets/json/mainpage.json"></script>
//code for what to do with this
another method is
$.getJSON("assets/json/mainpage.json")
You did not find two different methods.
The first version is not how it works.
You can load a JavaScript object that is using object notation using a script tag, so
<script type="text/javascript" src="assets/json/mainpage.js"></script>
could contain
var myJSObject = { "key":"value" };
whereas the second method will call something that returns (static or generated) content like
{ "key":"value" }
For example
$.getJSON("assets/json/mainpage.php");
would call a server process that would do
header("content-type: application/json");
echo '{ "key":"value" }';
If the assets/json/mainpage.json returns a pure JSON, the first method is totally wrong because the tag <script> is intended to serve some sort of scripting language, and a JSON is not a scripting language. It's not impossible to see something like this method, though. If the assets/json/mainpage.json supports JSON padding, mainly knows as JSONP, the following snippet is completely valid:
<script type="text/javascript" src="assets/json/mainpage.json?callback=fn"></script>
You can keep the .json extension (or any extension you like) as long as the server returns the result as a Content-Type: javascript/text on the response header and wraps the result in the callback function. Note that the value of the callback param must be a name of a function that is globally accessible.
The second method is the same as doing an ajax call to the JSON and parsing its content. This is the one you should use, between the two. Although it's kind of useless without a callback or promise for response.
$.getJSON("assets/json/mainpage.json").done(function(res) { /* handle response */ });
Hope it helps.

Programmatically view content of html element loaded from another file

I would like to get the contents of a file on the server into a string. What is the easiest way to do this? Right now I am trying:
<script type="text/template" src="partials/someTemplate.html"
id="someTemplate"></script>
<script>
console.log($('#someTemplate').html()); //nothing comes up
</script>
A hacky way to do this is:
$('<div>').appendTo(document.body)
.load('partials/someTemplate.html', function () {console.log(this.innerHTML);} );
and then get the innerHTML of that, but that's a waste of an HTML element. Any thoughts? I feel like this should be silly easy.
Just use $.get():
var html;
$.get('partials/someTemplate.html', function(res)
{
html = res;
});
You basically need to use an asynchronous server request (ajax) to get the content of a file and process it later.
This can be done in pure JavaScript using XMLHttpRequest but the most popular and easiest way to do this is using jQuery's $.ajax function.
$.ajax({
url: "partials/someTemplate.html"
}).done(function( content ) {
console.log( "Your returned content is " + content );
});
You can configure this ajax call in many ways as described in documentation, you can pass parameters to the file, cache the request or demand a specific content type to be returned if that is necessary, but given example would do just fine for what you are trying to accomplish.
Please note that there are many ways to do an ajax request in jQuery, like .load(), $.post(), $.get(), $.getScript() and $.getJSON() but those are all just shorthand methods for an Ajax request so if you use those you are basically using an $.ajax with some predefined parameters.
Also, make sure that you need to use JavaScript and an async request at all. Getting content of a file inside some other file is mostly often done using some server side processing language like PHP (require() and include()),.NET, Java etc., and while that seems obvious for some people I felt obligated to say that since you didn't provide enaugh information about why you need that content and what you want to do with it.

Using JSON data in a javascript function

I am returing JSON data as a response in a web service I am writing.
I am wondering what is the best way to consume the data, returned to a Javascript function (passed as an argument).
Do I:
use eval()
use Doug Crawfords jSon parser to parse the JSON data into a Javascript object
simply use the returned data as an object literal
BTW, I am still learning Javascript, (just started reading the Definitive Guide 2 days ago) so if my question seems a bit naive or asinine - bear with me.
I would suggest a few things, first, on the web service side:
If a callback=functionName parameter is passed in the query string, then return the properly serialized JSON as the only parameter to the callback function (In this case functionName
If no callback was requested, then simply return the properly serialized JSON string. (This is helpful for when other languages consume the JSON. PHP or Ruby for instance)
Then, as far as consuming it, if you are on the same domain as the web service, you can retrieve the code and use the json2.js parser to parse it. If you are on a separate domain, use the callback parameter when requesting the data, and make sure you set up a function to handle the callback.
Simple example (Using PHP):
<?php
$callback = null;
if( isset($_REQUEST['callback']) ){
$callback = $_REQUEST['callback'];
}
$fakeData = array( 'key' => 'value');
$json = json_encode( $fakeData );
echo $callback ? "$callback($json)" : $json;
?>
JS (On different domain than the web service):
function handleCallback( data ){
alert( data.key );
}
function get_json(){
// Dynamically create the script element
var script = document.createElement('script');
script.type = "text/javascript";
script.src = "http://yourwebservice.com/service/?callback=handleCallback";
document.getElementsByTagName('head')[0].appendChild( script );
}
Calling get_json would dynamically create the request (as a script element due to cross domain restrictions. You can't use XMLHttpRequest to make cross domain requests in most browsers), and the PHP returned script would correctly call the handleCallback function when the script returns.
If you are using jQuery you can set it up so it returns as a JSON object.
http://api.jquery.com/jQuery.getJSON/
Assuming that your webservice is decorated with ScriptService attribute:
I would suggest using json2.js to handle the json clientside. It defers to native implementations when they are available.
(1). use eval()
Only if you're certain the data is clean. I'd never trust anything from an outside source.
(2). use Doug Crawfords jSon parser to parse the JSON data into a Javascript object
Best idea overall. Even jQuery uses plain old eval() to parse JSON.
(3). simply use the returned data as an object literal
When it's returned, it's just a string, not an object unless passed through one of the two aforementioned functions, or wrapped in a function ala JSONP.

Categories