Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JavaScript: Encapsulate context during loops that create listeners with shared values

Language/Tools For Problem:

Firebase and Vanilla JavaScript


My Problem:

When looping- I'm trying to encapsulate the context of the creation of 2 listeners and a boolean they both manipulate,

The problems with preserving the context:

  • Without binding - the for loop index counter is not encapsulated but ends being the same size of the list.

  • With the binding - The shared context of the boolean is lost.


My Code:

In each loop create 2 listeners and 1 boolean they share

1) value - Does the Original Fetch Of Messages

2) child-added - Also does Original Fetch(MUST BE SKIPPED) and later gets updates when boolean is set to true

3) messagesLoaded - A boolean that signifies that child-added events can now be listened for.

//LOOPING THROUGH THREAD IDS EG. [-K1234ASDFADFA,-K43123414234F ]
for(var i = 0; i < threadIDs.length; i++) { //INSIDE LOOP,USING CORE STRATEGY.
  var messagesLoaded = false;

    //FIRST: Load all the Messages of a thread

  var threadRef = firebaseThreadRef.child(threadIDs[i]);
  threadRef.on("value",function(snapshot) {   
    var thread = snapshot.val();
    messagesLoaded = true;
  });

    //SECOND: GET NEW MESSAGES AS THE ARE ADDED

  var messagesRef = threadInstanceRef.child("messages");
  var currentThreadId = threadIDs[i];                  

    //GRABBING TO BIND PARENT ID TO LISTENER

  messagesRef.on('child_added', function(snap) {
    if(messagesLoaded ) {                             
      //MESSAGESLOADED HAS LOST SCOPE!!!!
      var newThreadMessage = snap.val();
      newThreadMessage ["id"] = snap.key();
      receiveThreadMessage(newThreadMessage,this.instanceThreadID);
    }
  }.bind({instanceThreadID:currentThreadId}));

   /*WITHOUT BIND THE CORRECT INDEX 'i' WILL ALWAYS BE THE SIZE TO THE LIST 
    AND NOT WHAT IT WAS DURING THE ITERATION/*

}

The Failure in This Code:

  • The bind on the child_added was needed to keep the context of threadsIDs[i] when it is later fired.

  • BUT by binding, messagesLoaded is no longer shared between the 2 listeners.


The Question:

How can I correctly share "messagesLoaded" between to 2 event listeners?


Clarifications, if needed, on how the boolean should be used:

1) messagesLoaded is set to false during the loop(initialization-stage)

2) The on.("value"... loads and messagesLoaded is set to "true"(initialization-stage)

3) messagesLoaded sharing the updated context in the child_added listener which enables it(update-stage)

like image 730
Nick Pineda Avatar asked Nov 30 '25 06:11

Nick Pineda


1 Answers

This is kind of a shot in the dark because you have a lot going on there, but you're having a combination of issues - specifically async code and a closure in your for loop. This might get you closer.

for(var i = 0; i < threadIDs.length; i++) {
  firebaseThreadRef.child(threadIDs[i]).on("value", function(snapshot) {
    var thread = snapshot.val();
    (function(i){
      var currentThreadId = threadIDs[i];
      threadInstanceRef.child("messages").on('child_added', function(snap) {
        var newThreadMessage = snap.val();
        newThreadMessage ["id"] = snap.key();
        receiveThreadMessage(newThreadMessage, currentThreadId);
      });
    })(i)
  });
}
like image 192
Tyler McGinnis Avatar answered Dec 02 '25 19:12

Tyler McGinnis