Tips for sending an extra parameter to the callback function when using the loader.parse method in Three.js

The Parse method of the Loader object in three.js allows you to specify a callback function that will be triggered upon completion of the parsing process. This callback will receive a unique argument which represents the parsed object.

However, I am encountering an issue where I need to pass an additional argument to the callback function. This is because I am using the parse method within a loop and I want to create multiple callbacks, each with a specific value of a variable.

Currently, if I set this value within the loop but outside the callback function, the callback always receives the last value that was set in the loop. This is not the desired behavior.

Below is the code snippet:

for(var foldcont_index in foldcont) {
    var foldit = foldcont[foldcont_index];

    if(foldit.isDirectory()) {
        loadBFiles(fold+'/'+foldit.name);
    }

    if(foldit.isFile()) {
        var buigltf = fs.readFileSync(fold+'/'+foldit.name, 'utf8');
        loader.parse(
            buigltf,
            undefined,
            function(o) {
                var oname= // !!! before issue with foldit.name
                objectstank['xxx_'+oname]= o;
                loadpoint = loadpoint + loadpercentage;
                loadbar.set(loadpoint);
                if(loadpoint >= 100) { document.getElementById("load-bar").style.display = 'none'; }
            },
            undefined
        );
    }
}

Can anyone offer a solution to this issue?

Answer №1

Take a look at closures in JavaScript

Unlike in languages such as C/C++, JavaScript makes it easy to "close over variables," eliminating the need for extra parameters in callbacks. You can always access the necessary variables in a callback by using a closure.

In the specific case mentioned:

for(var foldcont_index in foldcont) {

    var foldit= foldcont[foldcont_index];

    if(foldit.isDirectory()) { loadBFiles(fold+'/'+foldit.name); }

    if(foldit.isFile()) {

      var buigltf= fs.readFileSync(fold+'/'+foldit.name, 'utf8');
      loader.parse(
          buigltf,
          undefined,
          function(oname) {
              return function(o) {
                  var oname= // !!! before issue with foldit.name
                  objectstank['xxx_'+oname]= o;
                  loadpoint= loadpoint+loadpercentage;
                  loadbar.set(loadpoint);
                  if(loadpoint>= 100) { document.getElementById("load- bar").style.display= 'none'; }
              };
          }(foldit.name),
          undefined
      );

    }
}

could potentially work. (I can understand your code). I am not aware of any Loader object within Three.js. There are several XXXLoader objects, but it is unclear which one you are using.

This pattern:

function(var1, var2, var3) {
   return function() {
      // do something with var1, var2, var3
   };
}(value1, value2, value3);

is a common pattern for closing over values. The code is a function that returns another function which has "closed" over var1, var2, and var3.

This allows you to pass the returned function to a callback. For example:

function makeCallback(var1, var2, var3) {
   return function() {
     console.log(var1, var2, var3);
   };
}

const fn = makeCallback('Hello', 'World', '!');
setTimeout(fn, 1000);

An inline version:

for (let i = 1; i <= 4; ++i) {
  setTimeout(function(var1) {
     return function() {
        console.log(var1);
     };
  }(i), i * 500);
}

Answer №2

This code snippet is a clear example of how to dynamically add "initially invisible" models to a scene and manage their visibility. The callback function in the class handles the addition of these models to the scene and a list, allowing for dynamic control over when and where they appear.

import { GLTFLoader } from 'https://cdn.skypack.dev/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="1b6f73697e7e5b2b352a2828352a">[email protected]</a>/examples/jsm/loaders/GLTFLoader.js'

export class transitVehicleSystem {

  constructor(scene, dParamWithUnits, numWedges) {

    this.scene = scene
    this.unallocatedTransitVehicleModels = []

    function prepareACallbackFunctionForLoader(myScene, myList) {
      return function( {scene} ) {
        const object = scene.children[0]
        object.visible = false
        for (let i=0; i<dParamWithUnits['numTransitVehicleModels'].value; i++) {
          const tempModel = object.clone()
          myScene.add(tempModel)
          myList.push(tempModel)
        }
      } 
    }
    const addTransitVehicles = prepareACallbackFunctionForLoader(this.scene, this.unallocatedTransitVehicleModels)

    const loader = new GLTFLoader()
    loader.load('models/TransitCar.glb',
      // pass in the callback function that was created within a closure
      addTransitVehicles,
      // called when loading is in progresses
      function ( xhr ) {
        console.log( ( xhr.loaded / xhr.total * 100 ) + '% transit car loaded' );
      },
      // called when loading has errors
      function ( error ) {
        console.log( 'An error happened', error );
      }
    )
  
    console.log(this.unallocatedTransitVehicleModels)
  
  }
*
*

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Instead of returning a single array of data from a form as expected, Jquery is returning two arrays

Having a bit of trouble with my code involving radio buttons and arrays using Jquery. I'm trying to record the selected values into one array, but it's creating separate arrays for each fieldset. Here's what I have: <script> $(doc ...

Formatting numbers as floating point values in AngularJS

I need a text box where users can enter an amount. The input should be restricted to numbers only, with no special characters or decimal points. I have managed this using custom filters. However, I also need the entered number to automatically display as ...

Mastering the Art of jQuery Function Chaining for Beginners

I want to change the name and ID of an element when a radio button is clicked. To avoid duplication of the selector, I tried setting it up this way: $( "#selectOther" ).click(function() { $( "[field=primaryInput]" ).attr('id', "modifiedId", ...

Prevent ui-select from being highlighted when clicked

here's a dilemma : (all in angular 1) I'm using a ui-select like this : https://i.stack.imgur.com/RzH2u.png Here's the code snippet : <div class="formZone-group"> <div class="mandatory-fl"> <div class="man ...

Problem with character encoding in Node.js

I am encountering an issue while retrieving data from a request, as the formatting or encoding is not matching my requirements. Attempted to address this by setting the encoding with req.setEncoding('utf8') The expected string should appear as: ...

Organizing data in TypeScript

Is there a way to alphabetically sort this list of objects by name using TypeScript? "[{name:"Prasanna",age:"22",sex:"Male",Designation:"System Engineer",Location:"Chennai"}, {name:"Nithya",age:"21",sex:"Female",Designation:"System Engineer",Location ...

Exploring an Array in Javascript derived from a PHP Array

I have a PHP variable named $TillArray that contains an array. I am trying to pass this array to a Javascript function in order to display an Alert message for each item within the array. Below is the code I have been using: <script type="text/javasc ...

Uh oh! You haven't set a QueryClient yet. Make sure to use QueryClientProvider to set

My first experience with React Query didn't go as planned when I encountered this error at the beginning of my React app: Even though I added QueryClientProvider to the top of my component tree, I kept getting: Error: No QueryClient set, use QueryCli ...

Obtaining information from node.js module to the server.js script

I am attempting to extract data from a function within a node module, which returns a JSON object. My goal is to display this JSON object in a router located in my server.js file. This is how I am trying to export it: // Function Export exports.g ...

Searching for values using keys in Angular

Currently, I am working on a project using Angular where I need to store information based on specific identifiers. To display this information in the Angular application, I am pulling data for different identifiers and showing it on the screen. At the mo ...

Leveraging Backbone.js without using client-side JavaScript

Exploring the idea of using Backbone.js and node.js to develop a compact web application. The concept of sharing code between the client and server is quite appealing. The challenge arises when considering how users without JavaScript-enabled browsers (in ...

using async.waterfall with async.apply

Here is a code snippet that I am working with: async.waterfall([ // Read directory async.apply(fs.readdir, '../testdata'), // Load data from each file function(files, callback) { async.each(files, loadDataFromFile, callback); } ], ...

Is there a way to prevent this JavaScript code from deleting the initial row of my table?

Looking at the code provided, it's evident that creating and deleting new rows is a straightforward process. However, there seems to be an issue where the default/origin/first row (A-T) gets deleted along with the rest of the rows. The main requiremen ...

Leveraging TypeScript to share information between directives in AngularJS through asynchronous calls

Although I've found some scattered information on how to tackle this issue, I haven't been able to find a solid solution. In my AngularJS application, I have an asynchronous call that fetches data from a server and I need to store it in a variab ...

Exploring the possibilities of utilizing React server components in my project

I am interested in experimenting with the new React API for making server-side component calls. However, I am unable to find any information on how to begin a project using server components. In an example of source code that I stumbled upon, it mentioned ...

Numerous documents within a JavaScript application

As a newcomer to JavaScript, I've been experimenting with the language to enhance my understanding. One aspect that puzzles me is how developers organize large JavaScript programs. In languages like Java, breaking down code into smaller files is commo ...

When it comes to adjusting the height of an element, there are two ways to go about it: using $(element).height

function adjustHeight(){ var headerHeight=$(element).find('.header').outerHeight(); console.log(headerHeight); var temp=$(window).height()-headerHeight; console.log(temp); $('.users ...

Can a single global variable be shared between a JavaScript file and a TypeScript file within an Angular project?

In my Angular 5 project, I am implementing a javascript library. If I create a global variable in my .js file, how can I access that variable from my .ts file? ...

Listening for button clicks in a Bootstrap drop down menu using JavaScript

I'm struggling to figure out how to detect button clicks in a drop-down menu. I've tried using Array.from to assign an event listener to each button in the drop-down, but it doesn't seem to work efficiently. It feels inefficient to assign in ...

Converting CSS code into JavaScript

I am currently working with the following code: .mr15 > * margin-right: 15px &:last-child margin-right: 0 I need help translating this code to Javascript. Should I use JQuery or pure Javascript for this scenario? Thank you. ...