cancel
Showing results for 
Search instead for 
Did you mean: 
cancel
Showing results for 
Search instead for 
Did you mean: 

Data URL instead of a XMLHTTPRequest, how?

SOLVED
Highlighted
Level 10

Data URL instead of a XMLHTTPRequest, how?

Help mentions this as a way to access local resources loaded in downloaded/offline experiences. Does anyone know what this method looks like in practice? I've spent a few hours Googleing and trying stuff without success. I have been using XMLHTTPRequest to load a local file of JSON data, but as noted it doens't work offline.

 

So if i have a local file at "app/resources/Uploaded/myfile.json" how would load this to a variable using the "Data URL" method? I can say that below does not work.

myData= JSON.parse("data:,/app/resources/Uploaded/myfile.json")
// or
myData = JSON.parse("data:/app/resources/Uploaded/myfile.json")

 

1 ACCEPTED SOLUTION

Accepted Solutions

Re: Data URL instead of a XMLHTTPRequest, how?

After trying every single method I could find on the internet I finally found one that does what I want. While @ClayHelberg proposed solution to use loadResourceScript does accomplish this it requires the object name to be in the JSON file which is not proper and makes it a JS file, as in the file needs to begin with myObjectName = { .... }, where a properly formatted JSON file should begin with just a curly brace "{". Having the name in the file creates dependencies between the JSON file and main JS file I don't want to manage. This was the benefit of my previous XMLHttp method you got to define the name of the object as you read it in.

 

So here is what worked for me, I have confirmed this works in both online and downloaded offline experiences.

 

$http.get('app/resources/Uploaded/test.json').success(function (data) {
    httpJSON = data;
    console.log('$http load = ', httpJSON); //test the load
});

 

10 REPLIES

Re: Data URL instead of a XMLHTTPRequest, how?

Do you have control of the JSON files, and are they static? If so, you could try moving the variable assignment into the file and then load it as a regular JS file with $scope.app.nf.loadResourceScript().

Re: Data URL instead of a XMLHTTPRequest, how?

@ClayHelberg thanks in advance for the help.

I think i'm having scope problems with this method. I can see the object loaded via loadResourceScript in the global scope in debug but i can't access it from my experience JS.

 

So if this what my JSON file "myJSONFile.json" looks like:

myJSON = {
   "0": {
      "name": {
         "first": "Bill",
         "last": "Barner"
      }
   },
   "1": {
      "name": {
         "first": "Joe",
         "last": "Smoe"
      }
   }
};

And i do this in the Home.JS:

$scope.app.fn.loadResourceScript("Uploaded/myJSONFile.json");
//that loads in to global scope

console.log(myJSON); //but something like this doesn't work

Re: Data URL instead of a XMLHTTPRequest, how?

You might need to stash it in the $scope to make it visible. So instead of

myJSON = {
  ...
}

try this:

$scope.myJSON = {
   ...
}

Re: Data URL instead of a XMLHTTPRequest, how?

Hey, I found your interesting post and tried it on my own. I took @jmikesell JSON file and safed it in the upload folder. 

I modified the code for the home.js a little bit:

 

$scope.readjson = function() {
$scope.app.fn.loadResourceScript("Uploaded/myJSONFile.json");
setTimeout(function () {
console.log(myJSON);
clearInterval(timerId);
}
, 500);
}

 

I found out, that, when calling the function once and without a time delay, you get an error:

"Uncaught ReferenceError: myJSON is not defined"

As soon, as you call it a second time or with a delay, everything works fine. 

Re: Data URL instead of a XMLHTTPRequest, how?

Yes, loadResourceScript() probably should have been defined to return a Promise, so you could write something like this:

$scope.readjson = function() {
  $scope.app.fn.loadResourceScript("Uploaded/myJSONFile.json")
    .then(function() { console.log(myJSON); });
}

The problem with the timeout approach is that it's not general. For example, if myJSONfile.json is very large, or if the data connection is slow, 500ms might not be long enough to ensure that the entire file is read and parsed.

 

After looking at it again, loadResourceScript() is probably not the best approach for this, due to these issues. It might be better to write your own version that handles the asynchronous loading better. Something like this:

$scope.asyncLoadScript = function (fname) {
  return new Promise((resolve, reject) => {
    if(fname) {
      var head = document.head || document.getElementsByTagName('head')[0],
          script = document.createElement('script');
      script.async = true;
      script.onload = resolve;
      script.onerror = reject;
      script.type = 'text/javascript';
      script.src=fname;
      head.appendChild(script);
    }
  });
}

Now you can use the promise to make sure your code doesn't try to use the JSON object before it's ready:

$scope.testJSON = function() {
  $scope.asyncLoadScript("app/resources/Uploaded/JSONTest.js")
    .then(function() { console.log(myJSON) }, 
          function() { console.log("Oops, something went wrong"); });
}

 

 

Re: Data URL instead of a XMLHTTPRequest, how?

Thanks, that works great!

Re: Data URL instead of a XMLHTTPRequest, how?

After trying every single method I could find on the internet I finally found one that does what I want. While @ClayHelberg proposed solution to use loadResourceScript does accomplish this it requires the object name to be in the JSON file which is not proper and makes it a JS file, as in the file needs to begin with myObjectName = { .... }, where a properly formatted JSON file should begin with just a curly brace "{". Having the name in the file creates dependencies between the JSON file and main JS file I don't want to manage. This was the benefit of my previous XMLHttp method you got to define the name of the object as you read it in.

 

So here is what worked for me, I have confirmed this works in both online and downloaded offline experiences.

 

$http.get('app/resources/Uploaded/test.json').success(function (data) {
    httpJSON = data;
    console.log('$http load = ', httpJSON); //test the load
});

 

Re: Data URL instead of a XMLHTTPRequest, how?

Yes, that's a much more elegant solution than mine. Nicely done!

Re: Data URL instead of a XMLHTTPRequest, how?

Is it also possible to write into the json-file?

I tried this:

$scope.jayson = function() {
var jsonfile = $http.get('app/resources/Uploaded/test.json');
var Username = $scope.app.mdl['CurrentSessionInfo'].svc['GetCurrentUser'].data[0].result;
console.log("Trying to save. Username: "+Username);

$http.post('app/resources/Uploaded/test.json',{'id': Username})
.success(function(response) {
$scope.usersData = response.users;
});
}

but it throws an error: 

ionic.bundle.min.js:135 POST http://localhost:3000/resource/TestTablet/dist/app/resources/Uploaded/test.json 405 (Method Not Allowed)