I had a coding interview quiz for front-end working with JSON and whatnot. I submitted my file but I'd just like to learn what I was missing.
And one of the reqs was Should not require a web server, and should be able to run offline.
.
I used jQuery
and used $.getJSON()
to get the data from the .JSON
file. I threw it up on my WAMP
localserver and it worked flawlessly across all three major browsers (IE, Firefox, Chrome). Then I moved that project to Desktop
, so essentally, without a LOCALSERVER.
On Firefox 30.0, it worked great. No problems.
Oon Google Chrome, I know you can't access local files without a web server...
On Internet Explorer 11, however... it didn't work. Why?
Here is what I am using. It's not complex.
function loadTasks() {
console.log("Loading tasks...");
$.getJSON("data.json", function(result) {
$.each(result, function(i, task) {
$("#load_tasks").append(
"<div class='row'><span class='data-task'>" + task.name +
"</span> <span class='data-date'>" + task.date +
"</span> <span class='data-name'>" + task.assigned +
"</span> </div>");
});
});
}
and here is data.json
I had a coding interview quiz for front-end working with JSON and whatnot. I submitted my file but I'd just like to learn what I was missing.
And one of the reqs was Should not require a web server, and should be able to run offline.
.
I used jQuery
and used $.getJSON()
to get the data from the .JSON
file. I threw it up on my WAMP
localserver and it worked flawlessly across all three major browsers (IE, Firefox, Chrome). Then I moved that project to Desktop
, so essentally, without a LOCALSERVER.
On Firefox 30.0, it worked great. No problems.
Oon Google Chrome, I know you can't access local files without a web server...
On Internet Explorer 11, however... it didn't work. Why?
Here is what I am using. It's not complex.
function loadTasks() {
console.log("Loading tasks...");
$.getJSON("data.json", function(result) {
$.each(result, function(i, task) {
$("#load_tasks").append(
"<div class='row'><span class='data-task'>" + task.name +
"</span> <span class='data-date'>" + task.date +
"</span> <span class='data-name'>" + task.assigned +
"</span> </div>");
});
});
}
and here is data.json
Share Improve this question edited Nov 16, 2015 at 16:53 Brian Tompsett - 汤莱恩 5,88372 gold badges61 silver badges133 bronze badges asked Jul 23, 2014 at 6:06 testtest 18.2k67 gold badges172 silver badges245 bronze badges 10- @SuperHornet in IE? No. – test Commented Jul 23, 2014 at 8:14
- do you see any data in result in debug mode? – Super Hornet Commented Jul 23, 2014 at 8:17
- Nothing... @SuperHornet – test Commented Jul 24, 2014 at 6:20
- 2 Also go to Internet Options>Advanced tab, check "Enable Active Content to run in files on My Computer". Can you reply with results of this? – Midhun Krishna Commented Jul 28, 2014 at 9:14
- 1 nyro.net/data.json does not exist... – Kai Hartmann Commented Aug 1, 2014 at 6:18
10 Answers
Reset to default 6 +250This seems to be a bug in jQuery. This bug has been reported to jQuery. The bugs status is fixed. But it seems, the bug is still at large.
Explanation
Generally in IE, ajax is implemented through ActiveXObjects. But in IE11, they made some tweaks to ActiveXObject implementation that if we try to do the following:
typeof(window.ActiveXObject)
instead of returning 'function', as it is said in IE docs, it returns undefined
. jQuery used to use this to switch between xhr in normal browsers and between one in IE. Since the check evaluates to undefined, code used to create xhr object in normal browsers is run.(which of-course is a bug, strangely, for non-local files it working fine).
In a bug filed to bugs.jquery.com, the bug reporter asks,
To fix the problem it's enough to change the condition: use "window.ActiveXObject !== undefined ?" instead of "window.ActiveXObject ?"
jQuery developers does try to fix this with this commit, but the comment under the commit says its still not fixed and also suggests a possible way to approach this problem.
var activex; // save activex somewhere so that it only need to check once
if ( activex === undefined )
try {
new ActiveXObject("MSXML2.XMLHTTP.3.0");
activex = true;
} catch (e) {
activex = false
}
xhr = activex ? createActiveXHR() : createStandardXHR();
I tried running your code in my machine and it works fine in IE. However if this is not running in your machine there should be some issue with IE settings. Apart from this if you want to read local file you can try the below code to resolve this issue for IE
function showData(){
function getLocalPath(fileName/*file name assuming in same directory*/){
// Remove any location or query part of the URL
var directoryPath = window.location.href.split("#")[0].split("?")[0];
var localPath;
if (directoryPath.charAt(9) == ":") {
localPath = unescape(directoryPath.substr(8)).replace(new RegExp("/","g"),"\\");
}
localPath = localPath.substring(0, localPath.lastIndexOf("\\")+1)+fileName;
console.log(localPath);
return localPath;
}
var content = null;
try {
var fileSystemObj = new ActiveXObject("Scripting.FileSystemObject");
var file = fileSystemObj.OpenTextFile(getLocalPath("data.json"),1);
content = file.ReadAll();
file.Close();
} catch(ex) {
console.log(ex);
}
console.log(content);
}
showData();
Run your html file in browser from file path and try running above function in console. It will output the content of json file in console.
You can create a wrapper for above code to use in XHR request. Let me know if you need help in integrating this with jQuery AJAX request.
What you we're missing was the use of appCache,
<html manifest="example.appcache">
in your HTACCESS add
AddType text/cache-manifest .appcache
inside example.appcache
CACHE MANIFEST
data.json
index.php
someimage.png
# continue for all the file needed for the web site to work
This means that once you have connected and downloaded the content once it's not needed again. on another note you not supposed to be able to access a file://
URI though XHR/ajax as there is no way to send the content if you wanted it offline you could have just embedded the content of the json file into you code as a string and just use var jsonStr = '{}'; var jsonObj = JSON.parse(jsonStr);
where jsonStr is you code. this would have meant no connections to the server as there would be no ajax/XHR request
jQuery .getJSON uses ajax. http://api.jquery.com/jquery.getjson/
.ajax uses a XMLHttpRequest
The web security of chrome and other browsers block XMLHttpRequest to local files because it is a security issue.
Via Security in Depth: Local Web Pages
http://blog.chromium.org/2008/12/security-in-depth-local-web-pages.html
You receive an email message from an attacker containing a web page as an attachment, which you download.
You open the now-local web page in your browser.
The local web page creates an iframe whose source is https://mail.google.com/mail/.
Because you are logged in to Gmail, the frame loads the messages in your inbox.
The local web page reads the contents of the frame by using JavaScript to access frames[0].document.documentElement.innerHTML. (An Internet web page would not be able to perform this step because it would come from a non-Gmail origin; the same-origin policy would cause the read to fail.)
The local web page places the contents of your inbox into a and submits the data via a form POST to the attacker's web server. Now the attacker has your inbox, which may be useful for spamming or identify theft.
The solution for data which does not need same-origin policy security, is padded json. Since jsonp is not a secure format for data. Jsonp does not have the same-origin policy.
/* secured json */
{
"one": "Singular sensation",
"two": "Beady little eyes",
"three": "Little birds pitch by my doorstep"
}
/* padded json aka jsonp */
Mycallback ({
"one": "Singular sensation",
"two": "Beady little eyes",
"three": "Little birds pitch by my doorstep"
});
Since with jsonp the json is wrapped in a valid javascript function it can be opened the same way as any one would add any javascript to a page.
var element = document.createElement("script");
element.src = "jsonp.js";
document.body.appendChild(element);
And your callback processes the data,
function Mycallback(jsondata) {
}
This is functionally the same as a ajax request but different because it is a jsonp request, which is actually easier.
jQuery libs do directly support jsonp as well http://api.jquery.com/jquery.getjson/ See the example using Flickr's JSONP API; unless one was aware of the dual standards they may not even notice that jsonp is being used.
(function() { /* jsonp request note callback in url, otherwise same json*/
var flickerAPI = "http://api.flickr.com/services/feeds/photos_public.gne?jsoncallback=?";
$.getJSON( flickerAPI, {
tags: "mount rainier",
tagmode: "any",
format: "json"
})
.done(function( data ) {
$.each( data.items, function( i, item ) {
$( "<img>" ).attr( "src", item.media.m ).appendTo( "#images" );
if ( i === 3 ) {
return false;
}
});
});
})();
Local access to json can be enabled but it is done differently depending on browswer.
Use --allow-file-access-from-files to enable it in chrome. https://code.google.com/p/chromium/issues/detail?id=40787
FYI: they are working on encripted json https://datatracker.ietf.org/doc/html/draft-ietf-jose-json-web-encryption-08 I am fairly certain that there will be no method of using this locally the intention is to make it really, really secure.
Source: https://stackoverflow.com/a/22368301/1845953
Posting the answer just in case somebody else runs into it. In my case IE was loading a version of jquery that apparently causes "JSON undefined" error. Here is what I did to solve it:
<!--[if lt IE 9]>
<script src="http://code.jquery.com/jquery-1.10.2.js"></script>
<![endif]-->
<!--[if gte IE 9]><!-->
<script src="http://code.jquery.com/jquery-2.0.3.js"></script>
<!--<![endif]-->
The latest one is jquery 2.1.1: direct link but it says:
(IE <9 not supported)
So I guess jquery 1.11.1: direct link
And I found out you can develop ajax and jquery stuff in Chrome on local files if you use Chrome with this flag: --allow-file-access-from-files
(source)
<meta http-equiv="X-UA-Compatible" content="IE=edge">
Try adding this meta tag and check in IE
Here's a working solution. I've included handlebars because it's cleaner.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>JSON TEST</title>
</head>
<body>
<div id="load-tasks">
</div>
<script src="jquery.min.js"></script>
<script src="handlebars.min.js"></script>
<script id="tasks-template" type="text/x-handlebars-template">
{{#each .}}
<div class="row">
<span class="data-task">
{{this.name}}
</span> <span class="data-date">
{{this.date}}
</span> <span class="data-name">
{{this.assigned}}
</span>
</div>
{{/each}}
</script>
<script>
$(function () {
var loadTasksContainer = $('#load-tasks'),
tasksTemplate = Handlebars.compile($('#tasks-template').html());
$.ajax({
type: "GET",
url: "data.json",
dataType: "json",
cache: false,
success: function (data) {
var html = tasksTemplate(data);
loadTasksContainer.append(html);
},
error: function (xhr, status, error) {
//log error and status
}
});
});
</script>
</body>
</html>
Using JSONP you could make this work for all browsers with or without a web server or even cross domain.
Example data.jsonp file:
loadTasks([
{name:"Task 1", date:"Date 1", assigned:"John Doe"},
{name:"Task 2", date:"Date 2", assigned:"Jane Doe"}
]);
Then on your page just load the data.jsonp using a script tag:
<script>
function loadTasks(tasks) {
$.each(tasks, function (i, task) {
$("#load_tasks").append(
"<div class='row'><span class='data-task'>" + task.name +
"</span> <span class='data-date'>" + task.date +
"</span> <span class='data-name'>" + task.assigned +
"</span> </div>");
});
}
</script>
<script src="data.jsonp"></script>
Try including an error
callback ; jqxhr.responseText
may still contain data.json
.
data.json
{"data":{"abc":[123]}}
json.html
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="jquery-1.11.1.min.js"></script>
<script type="text/javascript">
$(function() {
$.getJSON(document.location.protocol + "data.json")
.then(function(data, textStatus, jqxhr) {
var response = JSON.parse(data);
console.log(textStatus, response);
}
// `error` callback
, function(jqxhr, textStatus, errorThrown) {
var response = JSON.parse(jqxhr.responseText);
console.log(textStatus, errorThrown, response);
$("body").append(response.data.abc);
});
})
</script>
</head>
<body>
</body>
</html>
Dealing with this problem will lead you to anywhere. It is a difficult task and it could be easily solved using any http server.
If your problem is that it is difficult to set up one, try this: https://www.npmjs.org/package/http-server
On your shell you go to the directory where are your files and then you just type
http-server ./ -p 12345
where 12345
can be changed by any valid and not already used port of your choice.