Node Callback array undefined (empty value) - javascript

I im using node js to pass data from watcher every few seconds to function streamplay that stores id.ts filenames in array this works fine as it stores but when i callback from another function in my program i get undefined value from this array....and i can't figure out how it needs to be written:
var stream_play = [];
watch('/tmp/1_.m3u8', function(event, name) {
/* DEFINE - variables */
var ts = [];
ts.push(1);
streamplay(id, ts[ts.length-1]);
});
function streamplay(id, ts, callback) {
/* CHECH - ts */
if (ts !== 0) {
console.log('adding id..'+id+'...with ts...'+ts)
stream_play[id] = ts;
} else {
return callback(stream_play[id]);
}
}
And calling from main function in node like this:
streamplay(stream, 0, function(response) {
console.log('streaming ts file...'+response+'...to client...')
res.write(fs.readFileSync('/tmp/'+response));
})
I get this:
streaming ts file...undefined...to client...

Your function call, streamplay(stream, 0, function(response) { will end up falling through to your else condition in streamplay. This line is return callback(stream_play[id]); and the stream_play array is initialized, but empty. Accessing a non-existent element in a JavaScript array returns undefined.

I found the solution and another problem...the first example using callback works now like charm. The problem was that i have master process and worker process and i read on node js site that master and worker process can't share between variables values...so the new question is how to share master and worker process variables so that i can access from all worker process variables values from master?
I im doing clustering with this because of my huge server load and cpu clustering is must to go.

Related

How to trigger function based on API call and callback in 3rd party app

I am trying to listen for a javascript callback from a 3rd party app on my site. The app is minified so it is quite hard to reverse engineer. However, having used the Chrome debugger, the callback I want to capture is below, is there any way, I can trigger a function when that 'CollectEvent' callback is fired, with access to the 'email' variable? You can see in the console, that the callbacks are being created on the window, although of course they are named differently each time the code runs.
Recognising that I cannot edit that code directly as it is part of a 3rd party library.
!function() {
var _0x14bdc8 = {
'CollectEvent': function(_0x4a9e64, _0x3ac5b7) {
if (_0x4a9e64) {
_0x14bdc8[_0x304d('0xa7')] && (_0x30053a('COUPON_CODE_COOKIE_NAME', _0x4a9e64[_0x304d('0xd7')], 0x1),
_0x14bdc8[_0x304d('0x6a')]());
var _0x562cf7 = {
'shopId': _0x14bdc8[_0x304d('0xc2')],
'campaignId': _0x14bdc8[_0x304d('0x79')],
'email': encodeURIComponent(_0x4a9e64[_0x304d('0x23')]),
'code': _0x4a9e64['code'],
'customFields': encodeURIComponent(JSON[_0x304d('0x3')](_0x3ac5b7)),
'domain': window[_0x304d('0x73')][_0x304d('0x4a')],
'currentUrl': window[_0x304d('0x73')][_0x304d('0x6b')]
};
_0x14bdc8[_0x304d('0xa0')](_0x986b46 + '/api/wheelioapp/collectemail', _0x562cf7, function(_0xea4ea9) {
_0xea4ea9[_0x304d('0x89')] && _0x14bdc8[_0x304d('0x8f')](!0x1, !0x1, !0x0, !0x1);
});
} else
alert(_0x304d('0x80'));
},
...
}
}
You can see here the Wheelio app object in the console and the callbacks which have been created (although they have different names each session).
I just need to log it
Well, ok. We can't change functions created on-the-fly, but we can change other window functions.
For example we can use encodeURIComponent. See this line:
'email': encodeURIComponent(_0x4a9e64[_0x304d('0x23')]),
It means that somehow the email will go into the encodeURIComponent. Good, because we can read it there:
/* At the beginning */
// This is helper function, detects correct email:
function validateEmail(email) {
const re = /^(([^<>()\[\]\\.,;:\s#"]+(\.[^<>()\[\]\\.,;:\s#"]+)*)|(".+"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
return re.test(String(email).toLowerCase());
}
// Keep old function
let oldEncodeURIComponent = window.encodeURIComponent;
// Crete new one
window.encodeURIComponent = (data) => {
if (validateEmail(data)) {
// Gotcha!
console.log('[encodeURIComponent]', data);
}
return oldEncodeURIComponent(data);
}
/* Here program works as normal, but creates lots of logs... */
/* In the end */
// If we can understand when we need to stop looking for email,
// we will disconnect our function:
window.encodeURIComponent = oldEncodeURIComponent;
So the idea is to read all data passing thru encodeURIComponent.
P.S. Email validator is here

Copy a Parse.com class to new class with transformation of values

There is an existing Parse.com class that needs to be copied to a new Parse.com class with some new columns and the transformation of one of the columns. The code currently works and uses the Parse.Query.each method to iterate over all records as detailed in the Parse.com documentation but it stops processing at 831 records although there are 12k+ records in the class. This is odd given each should not have a limit and other default limits are 100 or 1000 for find. Should another method be used to iterate over all records or is there something wrong with the code?
var SourceObject = Parse.Object.extend("Log_Old_Class");
var source_query = new Parse.Query(SourceObject);
var TargetObject = Parse.Object.extend("Log_New_Class")
source_query.each(function(record) {
//save record to new class code works fine
var target_query = new TargetObject();
target_query.set("col1_new",record.col1);
target_query.set("col2_new",record.col2);
//etc...
target_query.save(null, {
success: function(obj) {
//SAVED
},
error: function(obj, error) {
//ERROR
}
});
}).then(function() {
//DONE
},
function(error) {
//error
});
One thing that comes to my mind immediately is that the function is getting timed-out. Parse has time limitations on each function. If I were you, I'd first load all the objects in the source class and then add them separately by having a delay between to API calls (server overload issues can also be present).

Invoking a JavaScript function from oncomplete handler of p:remoteCommand - simulating the same using some JavaScript code

Caution : Although this question covers long textual information with a mess of Java code snippets, it is merely targeted to JavaScript/jQuery and a bit of PrimeFaces stuff (just <p:remoteCommand>) as mentioned in the introductory part in the beginning.
I am receiving a JSON message from WebSockets (Java EE 7 / JSR 356 WebSocket API) as follows.
if (window.WebSocket) {
var ws = new WebSocket("wss://localhost:8181/ContextPath/AdminPush");
ws.onmessage = function (event) {
jsonMsg=event.data;
var json = JSON.parse(jsonMsg);
var msg=json["jsonMessage"];
if (window[msg]) {
window[msg](); //It is literally interpreted as a function - updateModel();
}
};
}
In the above code, event.data contains a JSON string {"jsonMessage":"updateModel"}. Thus, msg will contain a string value which is updateModel.
In the following segment of code,
if (window[msg]) {
window[msg](); //It is literally interpreted as a JavaScript function - updateModel();
}
window[msg](); causes a JavaScript function associated with a <p:remoteCommand> to be invoked (which in turn invokes an actionListener="#{bean.remoteAction}" associated with the <p:remoteCommand>).
<p:remoteCommand name="updateModel"
actionListener="#{bean.remoteAction}"
oncomplete="notifyAll()"
process="#this"
update="#none"/>
update="#none" is not necessarily needed.
After receiving this message, I need to notify all the associated clients about this update. I use the following JavaScript function to do so which is associated with the oncomplete handler of the above <p:remoteCommand>.
var jsonMsg;
function notifyAll() {
if(jsonMsg) {
sendMessage(jsonMsg);
}
}
Notice that the variable jsonMsg is already assigned a value in the first snippet - it is a global variable. sendMessage() is another JavaScript function that actually sends a notification about this update to all the associated clients through WebSockets which is not needed in this question.
This works well but is there a way to do some magic in the following condition
if (window[msg]) {
window[msg]();
//Do something to call notifyAll() on oncomplete of remote command.
}
so that the notifyAll() function can be invoked through some JavaScript code directly (which is currently attached to oncomplete of <p:remoteCommand> and the expected JavaScript code (or even something else) should simulate this oncomplete) basically eliminating the need to depend upon a global JavaScript variable (jsonMSg)?
Edit : The problem I am trying to solve (it may be considered to be additional information).
When an admin for example, makes some changes (by means of DML operations) to a JPA entity named Category, entity listeners are triggered which in turn causes a CDI event to be raised as follows.
#ApplicationScoped
public class CategoryListener {
#PostPersist
#PostUpdate
#PostRemove
public void onChange(Category category) throws NamingException {
BeanManager beanManager = (BeanManager) InitialContext.doLookup("java:comp/BeanManager");
beanManager.fireEvent(new CategoryChangeEvent(category));
}
}
Needless to say that the entity Category is designated with the annotation #EntityListeners(CategoryListener.class).
Just one side note (completely off topic) : Getting an instance of BeanManager through a JNDI look-up as done in the preceding code snippet is temporary. The GlassFish Server 4.1 having the Weld version 2.2.2 final fails to inject the CDI event javax.enterprise.event.Event<T> which is supposed to be injected as follows.
#Inject
private Event<CategoryChangeEvent> event;
And then, the event can be fired as follows with reference to the relevant code snippet above.
event.fire(new CategoryChangeEvent(category));
This event is observed in the web project as follows.
#ApplicationScoped
public class RealTimeUpdate {
public void onCategoryChange(#Observes CategoryChangeEvent event) {
AdminPush.sendAll("updateModel");
}
}
Where an admin uses his own end-point as follows (AdminPush.sendAll("updateModel"); is invoked manually therein).
#ServerEndpoint(value = "/AdminPush", configurator = ServletAwareConfig.class)
public final class AdminPush {
private static final Set<Session> sessions = new LinkedHashSet<Session>();
#OnOpen
public void onOpen(Session session, EndpointConfig config) {
if (Boolean.valueOf((String) config.getUserProperties().get("isAdmin"))) {
sessions.add(session);
}
}
#OnClose
public void onClose(Session session) {
sessions.remove(session);
}
private static JsonObject createJsonMessage(String message) {
return JsonProvider.provider().createObjectBuilder().add("jsonMessage", message).build();
}
public static void sendAll(String text) {
synchronized (sessions) {
String message = createJsonMessage(text).toString();
for (Session session : sessions) {
if (session.isOpen()) {
session.getAsyncRemote().sendText(message);
}
}
}
}
}
Here only an admin is allowed to use this end-point. All other users are prevented from creating a WebSocket session using a conditional check in the onOpen() method.
session.getAsyncRemote().sendText(message); inside the foreach loop sends a notification (in the form of a JSON message) to the admin about these changes made in the entity Category.
As shown in the first code snippet, window[msg](); invokes an action method (through a <p:remoteCommand> as shown earlier) associated with an application scoped bean - actionListener="#{realTimeMenuManagedBean.remoteAction}".
#Named
#ApplicationScoped
public class RealTimeMenuManagedBean {
#Inject
private ParentMenuBeanLocal service;
private List<Category> category;
private final Map<Long, List<SubCategory>> categoryMap = new LinkedHashMap<Long, List<SubCategory>>();
// Other lists and maps as and when required for a dynamic CSS menu.
public RealTimeMenuManagedBean() {}
#PostConstruct
private void init() {
populate();
}
private void populate() {
categoryMap.clear();
category = service.getCategoryList();
for (Category c : category) {
Long catId = c.getCatId();
categoryMap.put(catId, service.getSubCategoryList(catId));
}
}
// This method is invoked through the above-mentioned <p:remoteCommand>.
public void remoteAction() {
populate();
}
// Necessary accessor methods only.
}
All other users/clients (who are on a different panel - other than the admin panel) should only be notified when actionListener="#{realTimeMenuManagedBean.remoteAction}" finishes in its entirely - must not happen before the action method finishes - should be notified through the oncomplate event handler of <p:remoteCommand>. This is the reason why two different end-points have been taken.
Those other users use their own end-point:
#ServerEndpoint("/Push")
public final class Push {
private static final Set<Session> sessions = new LinkedHashSet<Session>();
#OnOpen
public void onOpen(Session session) {
sessions.add(session);
}
#OnClose
public void onClose(Session session) {
sessions.remove(session);
}
#OnMessage
public void onMessage(String text) {
synchronized (sessions) {
for (Session session : sessions) {
if (session.isOpen()) {
session.getAsyncRemote().sendText(text);
}
}
}
}
}
The method annotated with #OnMessage comes to play, when a message is sent through oncomplete of <p:remoteCommand> as shown above.
Those clients use the following JavaScript code to just fetch the new values from the above-mentioned application scoped bean (the bean was already queried adequately by the admin from the database. Thus, there is no need to ridiculously query it again by each and every individual client separately (other than the admin). Hence, it is an application scoped bean).
if (window.WebSocket) {
var ws = new WebSocket("wss://localhost:8181/ContextPath/Push");
ws.onmessage = function (event) {
var json = JSON.parse(event.data);
var msg = json["jsonMessage"];
if (window[msg]) {
window[msg]();
}
};
$(window).on('beforeunload', function () {
ws.close();
});
}
In conjunction with the following <p:remoteCommand>.
<p:remoteCommand name="updateModel"
process="#this"
update="parentMenu"/>
Where parentMenu - the component to be updated by this <p:remoteCommand> is an id of a container JSF component <h:panelGroup> which contains a plain CSS menu with a bunch of <ui:repeat>s.
Hope this makes the scenario clearer.
Update :
This question has been answered precisely here based on <p:remoteCommand> (As to the concrete question, the sole question was to remove a dependency upon a global JavaScript variable as stated in the introductory part of this question).
I don't think I understood every aspect of your problem, but anyway I try to help a bit. Note that I do not know PrimeFaces, so all I did was reading the docs.
What I understand is, that you try to get rid of the global variable. But I am afraid, I do not think this is possible.
The problem here is, that PrimeFaces does not allow you to pass something transparently from your invocation of the remote call further to the oncomplete call (except you pass it to a Java code of the Bean and then back to the UI, and this usually is not what you want).
However, I hope, you can come very close to it.
Part 1, JS returns early
Please also note that there probably is some misconception about Java and JavaScript.
Java is multithreaded and runs several commands in parallel, while JavaScript is singlethreaded and usually never waits for something to complete. Doing things asychronously is mandatory to get a responsive Web-UI.
Hence your remoteCommand invocation (seen from the JS side) will (usually, async case) return long before the oncomplete handler will be invoked. That means, if window[msg]() returns, you are not finished with the remoteCommand yet.
So what you want to manage with following code
if (window[msg]) {
window[msg]();
//Do something to call notifyAll() on oncomplete of remote command.
dosomethinghere();
}
will fail. dosomethinghere() will not be invoked when the remoteCommand returned (as JS does not want to wait for some event, which might never happen). This means, dosomethinghere() will be invoked when the Ajax-request was just opened to the remote (to the Java application).
To run something after the Ajax call finished, this must be done in the oncomplete routine (or onsuccess). This is why it's there.
Part 2, validate msg
Please note something different about window[msg](). This can be considered a bit dangerous if you cannot trust the pushed message completely. window[msg]() essentially runs any function named with the contents of the variable msg. For example if msg happen to be close then window.close() will be run, which probably is not what you want.
You should make sure, msg is one expected word, and decline all other words. Example code for this:
var validmsg = { updateModel:1, rc:1 }
[..]
if (validmsg[msg] && window[msg])
window[msg]();
Part 3: How to handle multiple JSON messages in parallel
The global variable has some drawback. There is only one. If you happen to receive another JSON message on the WebSocket while the previous message still is processing in the remoteCommand, this will overwrite the previous message. So the notifyAll() will see the newer message twice, the old one is lost.
A classical race condition. What you must do is, to create something like a registry to register all the messages, and then pass some value to notifyAll() to tell, which of the registered messages shall be processed.
With only a little change, you can either parallely (here) or serially (Part 4) process the messages.
First, create a counter to be able to distinguish the messages. Also an object to store all the messages. And we declare all valid messages we expect (see Part 2):
var jsonMsgNr = 0;
var jsonMessages = {};
var validmsg = { updateModel:1 }
Now add a message each time we receive one:
if (window.WebSocket) {
var ws = new WebSocket("wss://localhost:8181/ContextPath/AdminPush");
ws.onmessage = function (event) {
var jsonMsg = event.data;
var json = JSON.parse(jsonMsg);
var msg=json["jsonMessage"];
if (validmsg[msg] && window[msg]) {
var nr = ++jsonMsgNr;
jsonMessages[nr] = { jsonMsg:jsonMsg, json:json };
To be able to pass the nr to NotifyAll() an additional parameter needs to be passed to the Bean. Let's call it msgNr:
// Following might look a bit different on older PrimeFaces
window[msg]([{name:'msgNr', value:nr}]);
}
}
}
Perhaps have a look into https://stackoverflow.com/a/7221579/490291 for more on passing values this way.
The remoteAction bean now gets an additional parameter msgNr passed, which must be passed back via Ajax.
Unfortunately I have no idea (sorry) how this looks in Java. So make sure, your answer to the AjaxCall copies the msgNr out again.
Also, as the documentation is quiet about this subject, I am not sure how the parameters are passed back to the oncomplete handler. According to the JavaScript debugger, notifyAll() gets 3 parameters: xhdr, payload, and pfArgs. Unfortunately I was not able to setup a test case to find out how things look like.
Hence the function looks a bit like (bear with me, please):
function notifyAll(x, data, pfArgs) {
var nr = ???; // find out how to extract msgNr from data
var jsonMsg = jsonMessages[nr].jsonMsg;
var json = jsonMessages[nr].json;
jsonMessages[nr] = null; // free memory
sendMessage(jsonMsg);
dosomething(json);
}
If you split this into two functions, then you can invoke the notifyAll() from other parts in your application:
function notifyAll(x, data, unk) {
var nr = ???; // find out how to extract msgNr from data
realNotifyAll(nr);
}
function realNotifyAll(nr) {
if (!(nr in jsonMessages)) return;
var jsonMsg = jsonMessages[nr].jsonMsg;
var json = jsonMessages[nr].json;
delete jsonMessages[nr]; // free memory
sendMessage(jsonMsg);
dosomething(json);
}
Some things here are a bit redundant. For example you perhaps do not need the json element in jsonMessages or want to parse the json again to spare some memory in case the json is very big. However the code is meant not to be optimal but to be easy to adjust to your needs.
Part 4: serialize requests
Now to the changes to serialize things. That's quite easy by adding some semaphore. Semaphores in JavaScript are just variables. This is because there is only one global thread.
var jsonMsgNr = 0;
var jsonMessages = {};
var validmsg = { updateModel:1 }
var jsonMsgNrLast = 0; // ADDED
if (window.WebSocket) {
var ws = new WebSocket("wss://localhost:8181/ContextPath/AdminPush");
ws.onmessage = function (event) {
var jsonMsg = event.data;
var json = JSON.parse(jsonMsg);
var msg=json["jsonMessage"];
if (validmsg[msg] && window[msg]) {
var nr = ++jsonMsgNr;
jsonMessages[nr] = { jsonMsg:jsonMsg, json:json };
if (!jsonMsgNrLast) { // ADDED
jsonMsgNrLast = nr; // ADDED
window[msg]([{name:'msgNr', value:nr}]);
}
}
}
}
function realNotifyAll(nr) {
if (!(nr in jsonMessages)) return;
var jsonMsg = jsonMessages[nr].jsonMsg;
var json = jsonMessages[nr].json;
delete jsonMessages[nr]; // free memory
sendMessage(jsonMsg);
dosomething(json);
// Following ADDED
nr++;
jsonMsgNrLast = 0;
if (nr in jsonMessages)
{
jsonMsgNrLast = nr;
window[jsonMessages[nr].json.msg]([{name:'msgNr', value:nr}]);
}
}
Note: jsonMsgNrLast could be just a flag (true/false). However having the current processed number in a variable perhaps can help somewhere else.
Having said that, there is a starvation problem in case something fails in sendMessage or dosomething. So perhaps you can interleave it a bit:
function realNotifyAll(nr) {
if (!(nr in jsonMessages)) return;
var jsonMsg = jsonMessages[nr].jsonMsg;
var json = jsonMessages[nr].json;
delete jsonMessages[nr]; // free memory
nr++;
jsonMsgNrLast = 0;
if (nr in jsonMessages)
{
jsonMsgNrLast = nr;
// Be sure you are async here!
window[jsonMessages[nr].json.msg]([{name:'msgNr', value:nr}]);
}
// Moved, but now must not rely on jsonMsgNrLast:
sendMessage(jsonMsg);
dosomething(json);
}
This way the AJAX request is already send out while sendMessage is running. If now dosomething has a JavaScript error or similar, the messages are still processed correctly.
Please note: All this was typed in without any tests. There might be syntax errors or worse. Sorry, I tried my best. If you find a bug, edit is your friend.
Part 5: Direct Invocation from JS
Now, with all this in place and a serialized Run, you can always invoke the previous notifyAll() using realNotifyAll(jsonMsgNrLast). Or you can display the jsonMessages in a list and choose any arbitrary number.
By skipping the call to window[jsonMessages[nr].json.msg]([{name:'msgNr', value:nr}]); (and above window[msg]([{name:'msgNr', value:nr}]);) you also can halt the Bean processing and run it on-demand using the usual JQuery callbacks. For this create a function and change the code a bit again:
var jsonMsgNr = 0;
var jsonMessages = {};
var validmsg = { updateModel:1 }
var jsonMsgNrLast = 0;
var autoRun = true; // ADDED, set false control through GUI
if (window.WebSocket) {
var ws = new WebSocket("wss://localhost:8181/ContextPath/AdminPush");
ws.onmessage = function (event) {
var jsonMsg = event.data;
var json = JSON.parse(jsonMsg);
if (validmsg[msg] && window[msg]) {
var nr = ++jsonMsgNr;
jsonMessages[nr] = { jsonMsg:jsonMsg, json:json };
updateGuiPushList(nr, 1);
if (autoRun && !jsonMsgNrLast) {
runRemote(nr);
}
}
}
}
function realNotifyAll(nr) {
if (!(nr in jsonMessages)) return;
var jsonMsg = jsonMessages[nr].jsonMsg;
var json = jsonMessages[nr].json;
delete jsonMessages[nr]; // free memory
updateGuiPushList(nr, 0);
jsonMsgNrLast = 0;
if (autoRun)
runRemote(nr+1);
// Moved, but now must not rely on jsonMsgNrLast:
sendMessage(jsonMsg);
dosomething(json);
}
function runRemote(nr) {
if (nr==jsonMsgNrLast) return;
if (nr in jsonMessages)
{
if (jsonMsgNrLast) { alert("Whoopsie! Please wait until processing finished"); return; }
jsonMsgNrLast = nr;
updateGuiPushList(nr, 2);
// Be sure you are async here!
window[jsonMessages[nr].json.msg]([{name:'msgNr', value:nr}]);
}
}
Now you can start the processing with runRemote(nr) and invoke the completion function with realNotifyAll(nr).
The function updateGuiPushList(nr, state) with state=0:finished 1=added 2=running is the callback to your GUI code which updates the on-screen list of waiting pushes to process. Set autoRun=false to stop automatic processing and autoRun=true for automatic processing.
Note: After setting autoRun from false to true you need to trigger runRemote once with the lowest nr, of course.

How to make a clean Asynchronous loop?

Following typical REST standards, I broke up my resources into separate endpoints and calls. The main two objects in question here are List and Item (and of course, a list has a list of items, as well as some other data associated with it).
So if a user wants to retrieve his lists, he might make a Get request to api/Lists
Then the user might want to get the items in one of those lists and make a Get to api/ListItems/4 where 4 was found from List.listId retrieved in the previous call.
This is all well and good: the options.complete attribute of $.ajax lets me point to a callback method, so I can streamline these two events.
But things get very messy if I want to get the elements for all the lists in question. For example, let's assume I have a library function called makeGetRequest that takes in the end point and callback function, to make this code cleaner. Simply retrieving 3 elements the naive way results in this:
var success1 = function(elements){
var success2 = function(elements){
makeGetRequest("api/ListItems/3", finalSuccess);
}
makeGetRequest("api/ListItems/2", success2);
}
makeGetRequest("api/ListItems/1", success1);
Disgusting! This is the kind of thing in programming 101 we're smacked across the wrists for and pointed to loops. But how can you do this with a loop, without having to rely on external storage?
for(var i : values){
makeGetRequest("api/ListItems/" + i, successFunction);
}
function successFunction(items){
//I am called i-many times, each time only having ONE list's worth of items!
}
And even with storage, I would have to know when all have finished and retrieved their data, and call some master function that retrieves all the collected data and does something with it.
Is there a practice for handling this? This must have been solved many times before...
Try using a stack of endpoint parameters:
var params = [];
var results [];
params.push({endpoint: "api/ListItems/1"});
params.push({endpoint: "api/ListItems/2"});
params.push({endpoint: "api/ListItems/3"});
params.push({endpoint: "api/ListItems/4"});
Then you can make it recursive in your success handler:
function getResources(endPoint) {
var options = {} // Ajax Options
options.success = function (data) {
if (params.length > 0) {
results.push({endpoint: endpoint, data: data});
getResources(params.shift().endpoint);
}
else {
theMasterFunction(results)
}
}
$.get(endPoint, options)
}
And you can start it with a single call like this:
getResources(params.shift().endpoint);
Edit:
To keep everything self contained and out of global scope you can use a function and provide a callback:
function downloadResources(callback) {
var endpoints = [];
var results [];
endpoints.push({endpoint: "api/ListItems/1"});
endpoints.push({endpoint: "api/ListItems/2"});
endpoints.push({endpoint: "api/ListItems/3"});
endpoints.push({endpoint: "api/ListItems/4"});
function getResources(endPoint) {
var options = {} // Ajax Options
options.success = function (data) {
if (endpoints.length > 0) {
results.push({endpoint: endpoint, data: data});
getResources(endpoints.shift().endpoint);
}
else {
callback(results)
}
}
$.get(endPoint, options)
}
getResources(endpoints.shift().endpoint);
}
In use:
downloadResources(function(data) {
// Do stuff with your data set
});
dmck's answer is probably your best bet. However, another option is to do a bulk list option, so that your api supports requests like api/ListItems/?id=1&id=2&id=3.
You could also do an api search endpoint, if that fits your personal aesthetic more.

Access a parameter in Javascript

i've a strange problem with JS (probably a noob bug), but i'm stuck with it
In function fillInVersionsList, if i put an alert("tempo") or a break in firebug, i can access to my datas in parameter (ie : alert(pSimulator.simulatorData['LastVersion']) and i've the right result. The problem is that if i don't put an alert/firebug break before my access to datas, i've a JS error pSimulator.simulatorData is undefined.
$(document).ready(function() {
var simulator = new Simulator();
// Load SimulatorData into the simulator class
initSimulatorData(simulator);
// Fill in datas into VersionsList (2nd arg = Id of the list)
fillInVersionsList(simulator, $('#VersionsList'));
});
function initSimulatorData(pSimulator)
{
$.ajax({
url: "getData.php?action=init",
success: function(data) {
pSimulator.initSimulatorData(data);
}
});
}
function fillInVersionsList(pSimulator, pSelect)
{
//alert("tempo");
alert(pSimulator.simulatorData['LastVersion']);
pSelect.html('<option>test</option>')
}
function Simulator()
{
var simulatorData;
this.initSimulatorData = function(pSimulatorData)
{
this.simulatorData = pSimulatorData;
}
}
Is there something to solve this problem?
Thanks in advance
I suspect initSimulatorData is loading some data asynchronously.
Adding the alert gives it long enough for the data to be loaded.
You will need to add some sort of callback function, eg:
initSimulatorData(simulator, function () {
// Fill in datas into VersionsList (2nd arg = Id of the list)
fillInVersionsList(simulator, $('#VersionsList'));
});
Whats looks like from your problem is that simulator is taking time to initialize and when fillInVersionsList is called pSimulator is still not completely initalized.
When you put an alert it is getting some time delay by which time simulator is initalized.
Check if there is any callback method after simulator is completely initialized and then call fillInVersionsList method after that.
what does initSimulatorData(simulator) does? Is there any asynchronous code invloved in this?

Categories