load json into object and access from remote file - plain javascript - javascript

I'm trying to load several json files, store the responses in a global array, and access that array from yet another file.
So far I have the following:
on the page I creat the global object and include the callback function.
var globalObject = {};
function JsonCallback(j){
globalObject.dataArray.push(j);
};
in the remote file I have the following
(function(){
globalObject.dataArray = [];
globalObject.urlArray = [
'http://externaldomain.com.jsonp?uniqueID=1234&callback=JsonCallback',
'http://externaldomain.com.jsonp?uniqueID=1235&callback=JsonCallback',
'http://externaldomain.com.jsonp?uniqueID=1236&callback=JsonCallback',
'http://externaldomain.com.jsonp?uniqueID=1237&callback=JsonCallback'
];
var runFunction = function(index){
console.log(index);
console.log(globalObject.dataArray[index]);
// index doesn't match as files finish loading in different orders
};
var loadFunction = function(url, index){
var script = document.createElement("script");
script.onload = function(){
runFunction(index);
};
script.src = url;
document.getElementsByTagName("head")[0].appendChild(script);
};
var init = function(){
for(var i = 0;i<globalObject.urlArray.length;i++){
loadFunction(globalObject.urlArray[i], i);
}
}();
})();
for every url in the urlArray, I create a script element which loads the json file and fires the JsonCallback Function, storing the response in the global dataArray.
Once the file is loaded execute the runFunction, specific to the file just loaded. However, because the json files don't finish loading in the same order they were created, 'index' in runFunction doesn't always match the dataArray index.
Any ideas how to solve/avoid this problem would be very appreciated.

Related

Using SnapEngage methods in Angular Component throws an error

I am using SnapEngage widget for my application. The application has Angular Components and functions in it. I am trying to use SnapEngage methods (), but it doesnt invoke/recognize those methods. Please clarify if I should have a plugin/imports from SnapEngage. I am getting error as Cannot find name 'SnapEngage'. at the line SnapEngage.allowChatSound(true);
includeSnapEngageWidget(){
if( SnapEngageEnabled ==="true"){
var se = document.createElement('script');
var userEmail = email;
var userName = name;
se.type = 'text/javascript';
se.async = true;
se.src = '//storage.googleapis.com/code.snapengage.com/js/'+ widgetId +'.js';
var done = false;
se.onload = (se as any).onreadystatechange = function() {
if (!done&&(!this.readyState||this.readyState==='loaded'||this.readyState==='complete')) {
done = true;
/* Place your SnapEngage JS API code below */
SnapEngage.allowChatSound(true);
}
};
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(se, s);
}
}
strong text
If your application cannot find SnapEngage that means that js file wasn't loaded. Make sure that the call to '//storage.googleapis.com/code.snapengage.com/js/'+ widgetId +'.js'; has succeeded when your application is loaded.
Fixed it by creating an external *.js file and its *.d.ts file, referred the *.js file path in angular.cli.JSON under scripts. The imported the function in main.ts file and called the method inside angular.

How can I set a folder for After Effects to watch for JSON/text files?

I'm successfully using the following extend-script (with json2.js) to read a local JSON file, and change a text layer in my project. How could I modify this script so that, when ran, it continuously 'watches' for new JSON files that are added to the directory, and runs the rest of the script?
#include "json2.js" // jshint ignore:line
var script_file = File($.fileName); // get the location of the script file
var script_file_path = script_file.path; // get the path
var file_to_read = File(script_file_path + "/unique-job-id.json");
var my_JSON_object = null; // create an empty variable
var content; // this will hold the String content from the file
if(file_to_read !== false){// if it is really there
file_to_read.open('r'); // open it
content = file_to_read.read(); // read it
my_JSON_object = JSON.parse(content);// now evaluate the string from the file
//alert(my_JSON_object.arr[1]); // if it all went fine we have now a JSON Object instead of a string call length
var theComposition = app.project.item(1);
var theTextLayer = theComposition.layers[1];
theTextLayer.property("Source Text").setValue(my_JSON_object.arr[2]);
file_to_read.close(); // always close files after reading
}else{
alert("Error reading JSON"); // if something went wrong
}
Look at the Object Model:
Application scheduleTask() method
app.scheduleTask(stringToE xecute, delay, repeat)
Description:
Schedules the specified JavaScript for delayed execution.
So app.scheduleTask(string,delay,true) is exactly what you are looking for.Like this:
app.schduleTask('taskToWatchFile()',1000,true);
function taskToWatchFile(){
/*
*Add your code here
*/
}

Load multiple JSON files in pure JavaScript

I am new to JavaScript. I have already understood how to create an object from a JSON-file with JSON.Parse() and now I need to load multiple local JSONs into an array. I've been googling my problem for a while, but everything that I found was related to single JSON files.
Is there any way to do this in pure JavaScript without any libraries like jQuery and etc.?
P.S.: There is no need to work with web-server or else, the code is running locally.
To do this, you need to first get the actual files. Then, you should parse them.
// we need a function to load files
// done is a "callback" function
// so you call it once you're finished and pass whatever you want
// in this case, we're passing the `responseText` of the XML request
var loadFile = function (filePath, done) {
var xhr = new XMLHTTPRequest();
xhr.onload = function () { return done(this.responseText) }
xhr.open("GET", filePath, true);
xhr.send();
}
// paths to all of your files
var myFiles = [ "file1", "file2", "file3" ];
// where you want to store the data
var jsonData = [];
// loop through each file
myFiles.forEach(function (file, i) {
// and call loadFile
// note how a function is passed as the second parameter
// that's the callback function
loadFile(file, function (responseText) {
// we set jsonData[i] to the parse data since the requests
// will not necessarily come in order
// so we can't use JSONdata.push(JSON.parse(responseText));
// if the order doesn't matter, you can use push
jsonData[i] = JSON.parse(responseText);
// or you could choose not to store it in an array.
// whatever you decide to do with it, it is available as
// responseText within this scope (unparsed!)
}
})
If you can't make an XML Request, you can also use a file reader object:
var loadLocalFile = function (filePath, done) {
var fr = new FileReader();
fr.onload = function () { return done(this.result); }
fr.readAsText(filePath);
}
You can do something like this:
var file1 = JSON.parse(file1);
var file2 = JSON.parse(file2);
var file3 = JSON.parse(file3);
var myFileArray = [file1, file2, file3];
// Do other stuff
// ....
// Add another file to the array
var file4 = JSON.parse(file4);
myFileArray.push(file4);
If you already have an array of un-parsed files you could do this:
var myFileArray = [];
for(var i=0; i<unparsedFileArray.length; i++){
myFileArray.push(JON.parse(unparsedFileArray[i]));
}

Callback function after reading multiple files

I am doing something similar to http://www.html5rocks.com/en/tutorials/file/dndfiles/
What I'm doing is Im reading the contents of the selected files one at a time to validate that their lines pass some regex test. After done validating all files, I need to update (enable / disable) some buttons accordingly hence the call back function
Is it possible to have a call back function which will do something after everything is read?
HTML:
<input type="file" id="files" name="files[]" multiple />
Javascipt:
<script>
function handleFileSelect(evt) {
var files = evt.target.files; // FileList object
// files is a FileList of File objects. List some properties.
var validArray = [];
for (var i = 0, f; f = files[i]; i++) {
//Create new file reader
var r = new FileReader();
//On load call
r.onload = (function (f) {
return function (e) {
var contents = e.target.result;
var lines = contents.split('\n');
for(var i=0; i<lines.length; i++){
//Validate regex of line here
//If line does not pass, append file name to validArray and break
}
};
})(f);
r.readAsText(f);
}
}
document.getElementById('files').addEventListener('change', handleFileSelect, false);
</script>
Came here looking for a similar answer. I wanted to call a function after all files were loaded and processed. The solution provided by #Snuffleupagus did not work for me because the function was called after all the files were read, but before they had finished being processed in the onload function. I found a solution around this as follows (not sure if it is the 'cleanest' but it works for me).
var processedCount=0; // global variable
var totalFiles = 0; // global variable
function handleFileSelect(evt) {
var files = evt.target.files; // FileList object
totalFiles = files.length; // important
// files is a FileList of File objects. List some properties.
for (var i = 0, f; f = files[i]; i++) {
//Create new file reader
var r = new FileReader();
//On load call
r.onload = (function(theFile){
return function(){
onLoadHandler(this,theFile);
onLoadEndHandler();
};
})(f);
r.readAsText(f);
}
}
function onLoadEndHandler(){
processedCount++;
if(processedCount == totalFiles){
// do whatever - this code will run after everything has been loaded and processed
}
}
I tried to use r.onloadend but it was called too soon. I believe because my function 'onLoadHandler' takes a few seconds to process each file and onloadend is called when the file is done being loaded but before the code within 'onload' has finished running.
Absolutely. Callbacks are just passed as any other normal argument would be, so we'll end up adding another argument to handleFileSelect and changing the event listener to an anonymous function that calls handleFileSelect with the extra argument.
I set up a fiddle to give you a quick working demo.
function handleFileSelect(evt, cb) {
var files = evt.target.files; // FileList object
// files is a FileList of File objects. List some properties.
var output = [];
for (var i = 0, f; f = files[i]; i++) {
output.push('<li><strong>'+ escape(f.name) + '</strong>');
}
document.getElementById('list').innerHTML = '<ul>' + output.join('') + '</ul>';
if(cb) cb();
}
document.getElementById('files').addEventListener('change', function(e){handleFileSelect(e, function(){alert('all done');})}, false);​
Breaking it down - added an extra argument to handleFileSelect and at the end added if(cb) cb();. That just checks to see if cb exists, if it does, run it as a function.
Then when we go to bind the event handler instead of passing a reference to handleFileSelect we use an anonymous function - this lets us pass our extra argument.
The anonymous function inside of the anonymous function is just our callback, it could be a reference to a function if you'd rather.
A really clean way to do this is to use async.js reduce method. Async.js gives many nice ways to deal with multiple callbacks. You could use reduce to iterate through the array of file names, and build a reduced value which is an array of the valid lines:
<input type="file" id="files" name="files[]" multiple />
<script type='text/javascript' src='https://github.com/caolan/async/raw/master/lib/async.js'/>
<script>
var isValidLine = function(text){
// todo: implement
}
function handleFileSelect(evt) {
var files = evt.target.files; // FileList object
// reduce by starting with empty array in second argument -
// this gets built up with the valid array lines
async.reduce(files, [], function(validLinesSoFar, file, callback){
var r = new FileReader();
// Read file here:
r.onload = function (f) {
var contents = f.target.result;
var lines = contents.split('\n');
for(var i=0; i<lines.length; i++){
if isValidLine(lines[i])
validLinesSoFar.push(lines[i]);
}
callback(null, validLinesSoFar);
};
r.readAsText(file);
}, function(err, validLines){
// gets called after every file iterated through
// result is entire valid array
// do something here with valid array
});
}
document.getElementById('files').addEventListener('change', handleFileSelect, false);
</script>
I would take a look at jQuery's deferred object
Also a very relevant question that might be applicable to you.
How to fire a callback function after a for-loop is done in Jquery?

url callback function not working

How can I use the callback function properly cause it's not working.
I want to retrieve my json values from the server to the client side.
For starters I tried this to see if its working.
sample code
index.html
<button onClick = "Json()">Click Here</button>
my.js
function Json()
{
var url = "http://www.sample.com/test.js?callback=displayUser";
var script = document.createElement('script');
script.src = url;
document.body.appendChild(script);
}
function displayUser(json)
{
alert("working");
}
test.js
var obj = { "a": "hey", "b": "what?"}
but does not return any alert, so I guess it does not proceed to my displayUser function.
If you want displayUser() called in test.js, you have to have code in test.js that will call it. It won't get called just because you put it in the URL. You would need to code parse it out of the URL and then call it.
Or, alternatively, you can hook up a notification when the script has finished loading and just call displayUser() yourself from outside of test.js after test.js is fully loaded.
To detect when the external script file has loaded successfully and just call displayUser() yourself, see this reference.
If you want to get the callback value from the test.js script file itself and execute it from within test.js, this is the only way I know of to do it:
window.displayUser = function() {
// do whatever
}
var scripts = document.getElementsByTagName("script");
for (var i = 0; i < scripts.length; i++) {
var url = scripts[i].src;
// extract filename and callback parameter from the URL
var matches = url.match(/\/([^\/]+)\?.*callback=(.*?)(&|$)/);
if (matches && matches[1] == "test.js") {
// call the callback function
window[matches[2]]();
}
}
The script that is returned by "http://www.sample.com/test.js?callback=displayUser" actually has to be valid javascript and contain a call to displayUser.
test.js should have a call to dispayUser().

Categories

Resources