I am getting a very strange issue whereby when I try to extract the word document as a compressed file for processing in my MS Word Task Pane MVC app the third time, it will blow up.
Here is the code:
Office.context.document.getFileAsync(Office.FileType.Compressed, function (result) {
if (result.status == "succeeded") {
var file = result.value;
file.getSliceAsync(0, function (resultSlice) {
//DO SOMETHING
});
} else {
//TODO: Service fault handling?
}
});
The error code that comes up is 5001. I am not sure how to fix this.
Please let me know if you have any thoughts on this.
Additional Details:
From MSDN:
No more than two documents are allowed to be in memory; otherwise the
getFileAsync operation will fail. Use the File.closeAsync method to
close the file when you are finished working with it.
Make sure you call File.closeAsync before you read the file again - that could explain the issue you are seeing.
More at: https://msdn.microsoft.com/en-us/library/office/jj715284.aspx
I have an example about how to use this API correctly. Actually the current example in the MSDN is not very correct. This code is tested in Word.
// Usually we encode the data in base64 format before sending it to server.
function encodeBase64(docData) {
var s = "";
for (var i = 0; i < docData.length; i++)
s += String.fromCharCode(docData[i]);
return window.btoa(s);
}
// Call getFileAsync() to start the retrieving file process.
function getFileAsyncInternal() {
Office.context.document.getFileAsync("compressed", { sliceSize: 10240 }, function (asyncResult) {
if (asyncResult.status == Office.AsyncResultStatus.Failed) {
document.getElementById("log").textContent = JSON.stringify(asyncResult);
}
else {
getAllSlices(asyncResult.value);
}
});
}
// Get all the slices of file from the host after "getFileAsync" is done.
function getAllSlices(file) {
var sliceCount = file.sliceCount;
var sliceIndex = 0;
var docdata = [];
var getSlice = function () {
file.getSliceAsync(sliceIndex, function (asyncResult) {
if (asyncResult.status == "succeeded") {
docdata = docdata.concat(asyncResult.value.data);
sliceIndex++;
if (sliceIndex == sliceCount) {
file.closeAsync();
onGetAllSlicesSucceeded(docdata);
}
else {
getSlice();
}
}
else {
file.closeAsync();
document.getElementById("log").textContent = JSON.stringify(asyncResult);
}
});
};
getSlice();
}
// Upload the docx file to server after obtaining all the bits from host.
function onGetAllSlicesSucceeded(docxData) {
$.ajax({
type: "POST",
url: "Handler.ashx",
data: encodeBase64(docxData),
contentType: "application/json; charset=utf-8",
}).done(function (data) {
document.getElementById("documentXmlContent").textContent = data;
}).fail(function (jqXHR, textStatus) {
});
}
You may find more information from here:
https://github.com/pkkj/AppForOfficeSample/tree/master/GetFileAsync
Hope this could help.
Additional to Keyjing Peng's answer (which I found very helpful, thanks!) I thought I'd share a variation on the encodeBase64, which you don't want to do if you are uploading via REST to SharePoint. In that case you want to convert the byte array to a Uint8Array. Only then could I get it into a SharePoint library without file corruption.
var uArray = new Uint8Array(docdata);
Hope this helps someone, couldn't find this info anywhere else online...
See this link
http://msdn.microsoft.com/en-us/library/office/jj715284(v=office.1501401).aspx
it contains this example method:
var i = 0;
var slices = 0;
function getDocumentAsPDF() {
Office.context.document.getFileAsync("pdf",{sliceSize: 2097152}, function (result) {
if (result.status == "succeeded") {
// If the getFileAsync call succeeded, then
// result.value will return a valid File Object.
myFile = result.value;
slices = myFile.sliceCount;
document.getElementById("result").innerText = " File size:" + myFile.size + " #Slices: " + slices;
// Iterate over the file slices.
for ( i = 0; i < slices; i++) {
var slice = myFile.getSliceAsync(i, function (result) {
if (result.status == "succeeded") {
doSomethingWithChunk(result.value.data);
if (slices == i) // Means it's done traversing...
{
SendFileComplete();
}
}
else
document.getElementById("result").innerText = result.error.message;
});
}
myFile.closeAsync();
}
else
document.getElementById("result2").innerText = result.error.message;
});
}
change "pdf" to "compressed" and the method call doSomethingWithChunk() needs to be created and should probably do something like this:
function base64Encode(str) {
return btoa(encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, function (match, p1) {
return String.fromCharCode('0x' + p1);
}));
}
I use this technique to successfully save to Azure blob storage.
Obviously you should rename the method as well.
Related
function moveIt(result, finish) {
$result = $(result);
$result.find('#main-content-wrapper').appendTo('#aem-content');
$result.appendTo('#scriptDiv');
if (finish !== undefined) {
finish();
}
}
function isAuthSpace(path) {
if (path.toLowerCase().indexOf("shop/") > 0) return true;
return false;
}
function finishInjecting() {
ProcessInjection("div.dyna-prd-lnk", parseDivTag, pumpDivTag, "Shop.aspx/GetLinks");
}
function AEMLoadError(isAuth) {
var fileToLoad = "unAuth.html";
if (isAuth) {
fileToLoad = "auth.html";
}
$("#aem-content").load(fileToLoad, finishInjecting);
}
function breakAEMLoadPath(path) {
return BreakTheAEMLoadPath === true ? "2" : path;
}
function PullAEM(path, finish) {
var isAuth = isAuthSpace(path);
var ppath = breakAEMLoadPath(path);
$.ajax({
url: ppath,
success: function (result) {
moveIt(result, finish);
},
error: function () {
AEMLoadError(isAuth);
},
dataType: "html"
});
}
When I call the above function PullAEM(path, finish), no matter what value I put in path parameter, the ajax call calls the success function, if the path has garbage in it, say it's empty, the call succeeds (even though it should fail). When it should fail, the result contains the contents of the current page which is not what path is pointing to. Anyone have any idea what I'm doing wrong?
Thanks for everyone answering so fast. I'm not sure what the problem was but after I cleaned it all up to post it up here it worked great! Though, it ay have been something you both were saying.
This is working perfectly....
I have made an IRC bot for purely learning purposes but I have a Minecraft server that I use an API to get the status back as JSON. Now I have made the code and it works but for some reason when I try and use a return on the function so I can get the content it seems to not work?
So I have the two functions below:
function getservers(name) {
if (name == "proxy") {
var Request = unirest.get(proxy);
Request.header('Accept', 'application/json').end(function (response) {
main = response["raw_body"];
data = JSON.parse(main);
console.log(data["motd"]);
return data.motd;
});
} else if (name == "creative") {
var Request = unirest.get(creative);
Request.header('Accept', 'application/json').end(function (response) {
main = response["raw_body"];
data = JSON.parse(main);
return data;
});
} else if (name == "survival") {
var Request = unirest.get(survival);
Request.header('Accept', 'application/json').end(function (response) {
main = response["raw_body"];
data = JSON.parse(main);
return data;
});
}
}
// Main logic:
function parsemessage(msg, to) {
// Execute files
function pu(o,t,f){if(o)throw o;if(f)throw f;bot.say(to,t)}
if (msg.substring(0,1) == pre) {
// Get array
msgs = msg.split(' ');
console.log(msgs[0]);
// Run Login
if (msgs[0] == pre+"help") {
bot.say(to, "Help & Commands can be found here: https://server.dannysmc.com/bots.html");
} else if (msgs[0] == pre+"status") {
// Get status of server, should return online/offline - player count for each server - motd
server = getservers("proxy");
console.log(server);
/*var data = '';
var Request = unirest.get('https://mcapi.us/server/status?ip=185.38.149.35&port=25578');
Request.header('Accept', 'application/json').end(function (response) {
main = response["raw_body"];
data = JSON.parse(main);
});
} else if (msgs[0] == pre+"players") {
// Should return the player list for each server
} else if (msgs[0] == pre+"motd") {
// Should return the message of the day.
} else if (msgs[0] == pre+"ip") {
bot.say(to, "ShinexusUK IP Address: shinexusuk.nitrous.it");
} else if (msgs[0] == pre+"rules") {
}
}
}
The code in the getservers() function works, when I do the
console.log(data["motd"]);
It outputs my servers message of the day. But when I do return
data.motd
(same as data["motd"]?) The code that calls the function is here
server = getservers("proxy");
console.log(server);
Please note this is a node.js code and it contains many files so i can't exactly paste it. So here is the link to the github repo with the whole node application: Here
When the function getservers is called, it makes an asynchronous request and return nothing.
Then the callback is fired with the response of that request as parameter.
Note that the function getservers will end before the end callback of your request is called
(simplified version)
function getservers(name) {
var Request = unirest.get(proxy);
Request.header('Accept', 'application/json').end(function (response) {
main = response["raw_body"];
data = JSON.parse(main);
console.log(data["motd"]);
return data.motd;
});
// nothing returned here
}
What you need is a function callback that will be called after you got the response.
function getservers(name, callback) { // callback added
var Request = unirest.get(proxy);
Request.header('Accept', 'application/json').end(function (response) {
main = response["raw_body"];
data = JSON.parse(main);
console.log(data["motd"]);
callback(data.motd); // fire the callback with the data as parameter
});
// nothing returned here
}
And then you can use your function like this :
getservers("proxy", function(server){
console.log(server);
....
})
What I am trying to do here are:
Remove all contents in a class first, because every day the events.json file will be updated. I have my first question here: is there a better way to remove all contents from a database class on Parse?
Then I will send a request to get the events.json and store "name" and "id" of the result into a 2D array.
Then I will send multiple requests to get json files of each "name" and "id" pairs.
Finally, I will store the event detail into database. (one event per row) But now my code will terminate before it downloaded the json files.
Code:
function newLst(results) {
var event = Parse.Object.extend("event");
for (var i = 0; i < results.length; i++){
Parse.Cloud.httpRequest({
url: 'https://api.example.com/events/'+ results[i].name +'/'+ results[i].id +'.json',
success: function(newLst) {
var newJson = JSON.parse(newLst.text);
var newEvent = new event();
newEvent.set("eventId",newJson.data.id);
newEvent.set("eventName",newJson.data.title);
newEvent.save(null, {
success: function(newEvent) {
alert('New object created with objectId: ' + newEvent.id);
},
error: function(newEvent, error) {
alert('Failed to create new object, with error code: ' + error.message);
}
});
},
error: function(newLst) {
}
});
}
};
Parse.Cloud.job("getevent", function(request, status) {
var event = Parse.Object.extend("event");
var query = new Parse.Query(event);
query.notEqualTo("objectId", "lol");
query.limit(1000);
query.find({
success: function(results) {
for (var i = 0; i < results.length; i++) {
var myObject = results[i];
myObject.destroy({
success: function(myObject) {
},
error: function(myObject, error) {
}
});
}
},
error: function(error) {
alert("Error: " + error.code + " " + error.message);
}
});
var params = { url: 'https://api.example.com/events.json'};
Parse.Cloud.httpRequest(params).then(function(httpResponse) {
var results = [];
var jsonobj = JSON.parse(httpResponse.text);
for (var i = 0; i < jsonobj.data.length; i++) {
var tmp2D = {"name":"id"}
tmp2D.name = [jsonobj.data[i].name];
tmp2D.id = [jsonobj.data[i].id];
results.push(tmp2D);
}
newLst(results);
}).then(function() {
status.success("run job");
}, function(error) {
status.error(error);
});
});
I think my original answer is correct as a standalone. Rather than make it unreadable with the additional code, here it is made very specific to your edit.
The key is to eliminate passed callback functions. Everything below uses promises. Another key idea is decompose the activities into logical chunks.
A couple of caveats: (1) There's a lot of code there, and the chances that either your code is mistaken or mine is are still high, but this should communicate the gist of a better design. (2) We're doing enough work in these functions that we might bump into a parse-imposed timeout. Start out by testing all this with small counts.
Start with your question about destroying all instances of class...
// return a promise to destroy all instances of the "event" class
function destroyEvents() {
// is your event class really named with lowercase? uppercase is conventional
var query = new Parse.Query("event");
query.notEqualTo("objectId", "lol"); // doing this because the OP code did it. not sure why
query.limit(1000);
return query.find().then(function(results) {
return Parse.Object.destroyAll(results);
});
}
Next, get remote events and format them as simple JSON. See the comment. I'm pretty sure your idea of a "2D array" was ill-advised, but I may be misunderstanding your data...
// return a promise to fetch remote events and format them as an array of objects
//
// note - this differs from the OP data. this will evaluate to:
// [ { "name":"someName0", id:"someId0" }, { "name":"someName1", id:"someId1" }, ...]
//
// original code was producing:
// [ { "name":["someName0"], id:["someId0"] }, { "name":["someName1"], id:["someId1"] }, ...]
//
function fetchRemoteEvents() {
var params = { url: 'https://api.example.com/events.json'};
return Parse.Cloud.httpRequest(params).then(function(httpResponse) {
var results = [];
var remoteEvents = JSON.parse(httpResponse.text).data;
for (var i = 0; i < remoteEvents.length; i++) {
var remoteEvent = { "name": remoteEvents[i].name, "id": remoteEvents[i].id };
results.push(remoteEvent);
}
return results;
});
}
Please double check all of my work above regarding the format (e.g. response.text, JSON.parse().data, etc).
Its too easy to get confused when you mix callbacks and promises, and even worse when you're generating promises in a loop. Here again, we break out a simple operation, to create a single parse.com object based on one of the single remote events we got in the function above...
// return a promise to create a new native event based on a remoteEvent
function nativeEventFromRemoteEvent(remoteEvent) {
var url = 'https://api.example.com/events/'+ remoteEvent.name +'/'+ remoteEvent.id +'.json';
return Parse.Cloud.httpRequest({ url:url }).then(function(response) {
var eventDetail = JSON.parse(response.text).data;
var Event = Parse.Object.extend("event");
var event = new Event();
event.set("eventId", eventDetail.id);
event.set("eventName", eventDetail.title);
return event.save();
});
}
Finally, we can bring it together in a job that is simple to read, certain to do things in the desired order, and certain to call success() when (and only when) it finishes successfully...
// the parse job removes all events, fetches remote data that describe events
// then builds events from those descriptions
Parse.Cloud.job("getevent", function(request, status) {
destroyEvents().then(function() {
return fetchRemoteEvents();
}).then(function(remoteEvents) {
var newEventPromises = [];
for (var i = 0; i < remoteEvents.length; i++) {
var remoteEvent = remoteEvents[i];
newEventPromises.push(nativeEventFromRemoteEvent(remoteEvent));
}
return Parse.Promise.when(newEventPromises);
}).then(function() {
status.success("run job");
}, function(error) {
status.error(error);
});
});
The posted code does just one http request so there's no need for an array of promises or the invocation of Promise.when(). The rest of what might be happening is obscured by mixing the callback parameters to httpRequest with the promises and the assignment inside the push.
Here's a clarified rewrite:
Parse.Cloud.job("getevent", function(request, status) {
var promises = [];
var params = { url: 'https://api.example.com'};
Parse.Cloud.httpRequest(params).then(function(httpResponse) {
var results = [];
var jsonobj = JSON.parse(httpResponse.text);
for (var i = 0; i < jsonobj.data.length; i++) {
// some code
}
}).then(function() {
status.success("run job");
}, function(error) {
status.error(error);
});
});
But there's a very strong caveat here: this works only if ("// some code") that appears in your original post doesn't itself try to do any asynch work, database or otherwise.
Lets say you do need to do asynch work in that loop. Move that work to a promise-returning function collect those in an array, and then use Promise.when(). e.g....
// return a promise to look up some object, change it and save it...
function findChangeSave(someJSON) {
var query = new Parse.Query("SomeClass");
query.equalTo("someAttribute", someJSON.lookupAttribute);
return query.first().then(function(object) {
object.set("someOtherAttribute", someJSON.otherAttribute);
return object.save();
});
}
Then, in your loop...
var jsonobj = JSON.parse(httpResponse.text);
var promises = [];
for (var i = 0; i < jsonobj.data.length; i++) {
// some code, which is really:
var someJSON = jsonobj.data[i];
promises.push(findChangeSave(someJSON));
}
return Parse.Promise.when(promises);
I have some javascript code that updates some data to a database using a http handler, but this async call is made inside an .each loop. At the end of the loop I make a call to function CancelChanges() that refreshed the page. The problem is that the page seems to refresh before the database is updated. The .each loop seems to finish after the call to CancelChanges(). How can I make sure the page is refreshed after all the async calls are completed in the .each loop?
function SaveChanges() {
if (PreSaveValidation()) {
var allChangesSucceeded = true;
var studioId = $("#param_studio_id").val();
var baseDate = $("#param_selected_month").val().substring(6, 10) + $("#param_selected_month").val().substring(0,2);
var currency = "CAD";
var vacationPct = null;
var gvAdmissible = null;
$(".editable-unsaved").each( function() {
var newSalary = $(this).text();
var disciplineId = $(this).data("disciplineid");
var seniorityId = $(this).data("seniorityid");
var handlerCommand = "";
if ($(this).data("valuetype") === "inflated") {
handlerCommand = "AddAverageSalary";
} else if ($(this).data("valuetype") === "actual") {
handlerCommand = "UpdateAverageSalary";
}
$.get("WS/AverageSalary.ashx", { command: handlerCommand, studio_id: studioId, discipline_id: disciplineId, seniority_id: seniorityId, base_date: baseDate, currency: currency, salary: newSalary, vacation_pct: vacationPct, gv_admissible: gvAdmissible }).done(function (data) {
if (data != "1") {
$(this).removeClass("editable-unsaved");
allChangesSucceeded = true;
}
else {
alert('fail');
allChangesSucceeded = false;
}
});
});
if(allChangesSucceeded) CancelChanges();
}
}
function CancelChanges() {
var href = window.location.href;
href = href.split('#')[0];
window.location.href = href;
}
You could try using Promises and jQuery $.when
Store a list of the ajax call promises:
var defereds = [];
$(".editable-unsaved").each( function() {
//...
defereds.push($.get("WS/AverageSalary.ashx" /*...*/));
}
$.when.apply($, defereds).done(function() {
CancelChanges();
});
This should, hopefully, wait for all the ajax calls to finish before calling CancelChanges()
I think you need to change your structure a little bit, using a counter and calling CancelChanges when the counter equals the number of calls.
function SaveChanges() {
if (PreSaveValidation()) {
var studioId = $("#param_studio_id").val();
var baseDate = $("#param_selected_month").val().substring(6, 10) + $("#param_selected_month").val().substring(0,2);
var currency = "CAD";
var vacationPct = null;
var gvAdmissible = null;
var editableUnsaveds = $(".editable-unsaved"); //cache the selector here, because selectors are costly
var numOfGetsReturned = 0;
editableUnsaveds.each( function() {
var newSalary = $(this).text();
var disciplineId = $(this).data("disciplineid");
var seniorityId = $(this).data("seniorityid");
var handlerCommand = "";
if ($(this).data("valuetype") === "inflated") {
handlerCommand = "AddAverageSalary";
} else if ($(this).data("valuetype") === "actual") {
handlerCommand = "UpdateAverageSalary";
}
$.get("WS/AverageSalary.ashx", { command: handlerCommand, studio_id: studioId, discipline_id: disciplineId, seniority_id: seniorityId, base_date: baseDate, currency: currency, salary: newSalary, vacation_pct: vacationPct, gv_admissible: gvAdmissible }).done(function (data) {
if (data != "1") {
$(this).removeClass("editable-unsaved");
}
else {
alert('fail');
}
if(editableUnsaveds.length === ++numOfGetsReturned){
CancelChanges(); //now it should call when the final get call finishes.
}
});
});
}
}
function CancelChanges() {
var href = window.location.href;
href = href.split('#')[0];
window.location.href = href;
}
I'd use promises. The q library is my favorite way to implement them. But since you're using JQuery, I'd recommend following a similar approach to what I outline below, but using $.when, instead of q.allSettled
I often use promises when scraping tons of websites at once -- I need to iterate through a long list of websites, make requests for content, and do something with the content when the requests return. The last thing I want to do is send requests one at a time, handling each one as it returns.
In the abstract, that looks something like this:
function scrapeFromMany() {
var promises = [];
_.forEach(urls, function(url) {
// this makes the request
var promise = scraper(url);
// this stores the promise with the others you iterate through
promises.push(promise);
});
q.allSettled(promises).then(function(res) {
// this function is executed when all of the promises (requests) have been resolved
console.log("Everything is done -- do something with the results.", res);
});
}
Fwiw, promises aren't that easy to grok if you've never used them. If that's the case, plan on spending some time getting up to speed with the concepts. They'll change (for the much much better) the way you write async javascript, and they really are the blessed path with these sorts of operations.
Asynchronously call your check function within the "done" function handler. Keep track of how many requests have completed, and only do your processing once that's equal to the total number of expected requests.
if (PreSaveValidation()) {
var allChangesSucceeded = true;
var length = $(".editable-unsaved").length;
var completedCount = 0;
// ...
$(".editable-unsaved").each( function() {
// ...
$.get("WS/AverageSalary.ashx", data).done(function (data) {
completedCount++;
if (data != "1") {
$(this).removeClass("editable-unsaved");
// don't set all changes succeeded to true here
}
else {
alert('fail');
allChangesSucceeded = false;
}
isComplete(length, completedCount, allChangesSucceeded);
});
});
}
function isComplete(totalLength, currentLength, allChangesSucceeded) {
if (currentLength == totalLength) {
// should this be !allChangesSucceeded?
if (allChangesSucceeded) CancelChanges();
}
}
This happens because you are not waiting for the requests to complete to proceed with the loop.
To achieve so you have to set the "async" flag to false.
The call to the server should be like this:
$.ajax({
url: "WS/AverageSalary.ashx",
async: false,
data:{ command: handlerCommand, studio_id: studioId, discipline_id: disciplineId, seniority_id: seniorityId, base_date: baseDate, currency: currency, salary: newSalary, vacation_pct: vacationPct, gv_admissible: gvAdmissible },
success: function (data) {
if (data != "1") {
$(this).removeClass("editable-unsaved");
allChangesSucceeded = true;
}
else {
alert('fail');
allChangesSucceeded = false;
}
}
});
I have the following code grabbing a JSON object from github and I am tring to add certain parts to an array.
function getTree(hash) {
var pathToTree, returnedJSON;
pathToTree = 'https://api.github.com/repos/myaccount/myrepo/git/trees/' + hash;
$.ajax({
accepts: 'application/vnd.github-blob.raw',
dataType: 'jsonp',
url: pathToTree,
success: function (json) {
returnedJSON = json;
},
error: function (error) {
console.debug(error);
}
});
return returnedJSON;
}
function parseTree(hash) {
var objectedJSON, objectList = [], i, entry;
objectedJSON = getTree(hash, function () {
console.debug(objectedJSON); // this is not appearing in console
for (i = 0; i < objectedJSON.data.tree.length; i += 1) {
entry = objectedJSON.data.tree[i];
console.debug(entry);
if (entry.type === 'blob') {
if (entry.type.slice(-4) === '.svg') { // we only want the svg images not the ignore file and README etc
objectList.append(i.content);
}
} else if (entry.type === 'tree') {
objectList.append(parseTree(getTree(entry.sha)));
}
}
});
return objectList;
}
$(document).ready(function () {
var objects = parseTree('master', function () {
console.debug(objects);
});
});
I have the code retrieving the JSON object fine but I run into trouble when trying to get it parsed (aka pulling out the bits I want). The callbacks I am using do not seem to be going and was wondering if someone could look it over and help me out.
Specifically, can I add a callback to any function I choose? Do I have to do anything to that function?
I have fixed the code to illustrate how you would go about it.
function getTree(hash, cb) {
// notice that I copy the callback and hash references to have access to them in this
// function's closure and any subsequent closures, like the success and error
// callbacks.
var pathToTree, returnedJSON, cb = cb, hash = hash;
pathToTree = 'https://api.github.com/repos/myaccount/myrepo/git/trees/' + hash;
$.ajax({
accepts: 'application/vnd.github-blob.raw',
dataType: 'jsonp',
url: pathToTree,
success: function (json) {
returnedJSON = json;
// if anything was passed, call it.
if (cb) cb(json);
},
error: function (error) {
console.debug(error);
// an error happened, check it out.
throw error;
}
});
return returnedJSON;
}
function parseTree(hash) {
var objectedJSON, objectList = [], i, entry;
objectedJSON = getTree(hash, function (objectedJSON) {
console.debug(objectedJSON); // this is not appearing in console
for (i = 0; i < objectedJSON.data.tree.length; i += 1) {
entry = objectedJSON.data.tree[i];
console.debug(entry);
if (entry.type === 'blob') {
if (entry.type.slice(-4) === '.svg') { // we only want the svg images not the ignore file and README etc
objectList.append(i.content);
}
} else if (entry.type === 'tree') {
objectList.append(parseTree(getTree(entry.sha)));
}
}
});
return objectList;
}
$(document).ready(function () {
var objects = parseTree('master', function () {
console.debug(objects);
});
});
As far as I can see it, you are not passing callback to your functions:
function getTree(hash) {
And you are using like:
objectedJSON = getTree(hash, function () {
Similarly this function does not have callback param:
function parseTree(hash) {
And you are using like:
var objects = parseTree('master', function () {
Modify your functions like this:
function getTree(hash, fn) { ... }
function parseTree(hash, fn) { ... }
And then call fn using fn() when needed.
Add a second parameter o getTree function. Something like
function getTree(hash, callback)
And use a "jsopCallback" parameter in your Ajax options
$.ajax({
...
jsopCallback: callback,
...