RomanLarionov RomanLarionov - 3 months ago 28
Javascript Question

Javascript members not updated after function call

I am trying create a simple three.js app, but I'm getting stuck on some of the nuances of javascript. I don't really know how to explain the problem without an example:

var Model = function() {
THREE.Object3D.call(this);
this.loadedMesh = null;
this.meshIsLoaded = false;
};

Model.prototype = {
constructor: Model,

load: function(path, mtlName, objName) {
var onProgress = function(xhr) {...};

var onError = function(err) {...};

THREE.Loader.Handlers.add( /\.dds$/i, new THREE.DDSLoader());
mtlLoader.setPath(path);
mtlLoader.load(mtlName, function(materials) {
materials.preload();
objLoader.setMaterials(materials);
objLoader.setPath(path);
objLoader.load(objName, function(object) {
object.position.set(0, -5, 10);
object.scale.set(5, 5, 5);
object.rotation.y = Math.PI; // 180 degrees
scene.add(object);
this.loadedMesh = object;
this.meshIsLoaded = true;
});
}, onProgress, onError);
}
};


This wrapper should be a container for a three model. The loading works fine, but when I try and save the Model into a variable, none of the internal members are altered outside of the Model scope.

var spaceman = new Model();
spaceman.load("ACES/", "acesjustforroomshow.mtl", "acesjustforroomshow.obj");
...
function update() {
if (spaceman.meshIsLoaded)
spaceman.loadedMesh.rotation.x += 0.1;
}


It's weird because if I debug the app and wait until the model is loaded, I can hover over the internal members and they are populated. When I hover over the spaceman object, the values for loadedMesh and meshIsLoaded remain the default.

Is there some aspect of prototyping that I'm not understanding here?

Answer

My guess is that the issue is the this variable. Within the callback function you're passing to objLoader.load, it may no longer be set to your object. If I'm right, either of the below fixes should work:

Using bind:

objLoader.load(objName, function(object) {
    object.position.set(0, -5, 10);
    object.scale.set(5, 5, 5);
    object.rotation.y = Math.PI; // 180 degrees
    scene.add(object);
    this.loadedMesh = object;
    this.meshIsLoaded = true;
}.bind(this));

Capturing this in another variable:

var that = this;
objLoader.load(objName, function(object) {
    object.position.set(0, -5, 10);
    object.scale.set(5, 5, 5);
    object.rotation.y = Math.PI; // 180 degrees
    scene.add(object);
    that.loadedMesh = object;
    that.meshIsLoaded = true;
});