The animation in ThreeJs encounters context issues within Angular 2

I am trying to incorporate ThreeJs into my Angular 2 project. I have successfully rendered a scene with a simple cube, but I ran into an issue when using the animate() function. Here is the code snippet:

import { OnInit, Component } from '@angular/core';

const THREE = require('three');

@Component({
  selector: 'app-threejsscene',
  templateUrl: 'threejsscene.component.html'
})
export class ThreeJsSceneComponent implements OnInit {

  scene: THREE.Scene;
  renderer: THREE.Renderer;
  mesh: any;
  camera: THREE.Camera;
  geometry: THREE.Geometry;
  material: THREE.Material;


  ngOnInit() {

    this.scene = new THREE.Scene();

    this.camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 1, 10000 );
    this.camera.position.z = 1000;

    this.geometry = new THREE.BoxGeometry( 200, 200, 200 );
    this.material = new THREE.MeshBasicMaterial( { color: 0xff0000, wireframe: true } );

    this.mesh = new THREE.Mesh( this.geometry, this.material );
    this.scene.add( this.mesh );

    this.renderer = new THREE.WebGLRenderer();
    this.renderer.setSize( window.innerWidth, window.innerHeight );

    document.body.appendChild( this.renderer.domElement );
    this.animate();
  }

  protected animate() {
    requestAnimationFrame(() => this.animate());

    this.mesh.rotation.x += 1;
    this.mesh.rotation.y += 1;

    this.renderer.render( this.scene, this.camera );

  }
}

When calling this.animate() inside of ngOnInit(), the scene renders and applies rotation once. However, upon calling requestAnimationFrame, I encounter an error stating that "this" is undefined. It seems like the context of "this" referring to the class is lost.

My question is: Is there a correct or best practice to maintain the context of "this", or is there an alternative method to run the animation loop smoothly? Any help would be greatly appreciated!

Answer №1

Found a solution to the problem at hand. It may not be the most elegant, and I am open to changing it if someone comes up with a better one. I introduced a new field in the class called animateCallback and modified the code inside ngOnInit to use this instead of the previous "this.animate()".

this.animateCallback = {
      callAnimate: (this.animate).bind(this)
    };
    this.animateCallback.callAnimate();

The animate function now looks like this:

protected animate() {
    requestAnimationFrame( this.animateCallback.callAnimate );

    this.mesh.rotation.x += 1;
    this.mesh.rotation.y += 1;

    this.renderer.render( this.scene, this.camera );

  }

Answer №2

/**
      * This method creates a new function by binding the specified object as the this keyword and providing initial parameters.
      * @param thisArg The object to be associated with the this keyword inside the newly created function.
      * @param argArray A list of arguments to pass to the new function.
      */
    bind(this: Function, thisArg: any, ...argArray: any[]): any;

When I implement this, my update functions look something like this:

update () {
    // Set up the next frame.
    requestAnimationFrame(this.update.bind(this));
    // Render the scene.
    this.renderer.render(this.scene, this.camera);
  }

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

How to access the Parent ViewContainerRef within a projected child component in Angular 5

I have a unique application structure where the App component contains dynamically created components. The Parent component utilizes an <ng-content> element for projecting child components inside itself. App Component: @Component({ selector: &apo ...

Managed the double-click event to select Snap.svg text

I am currently utilizing the snapsvg library for a project where I am implementing the dblclick event to trigger a browser window alert. However, when clicking on the svg canvas, not only does the alert pop up but some text on the canvas also gets selected ...

Sending information across React context

I've encountered a challenge when trying to transfer data from one context to another in React. The job data I receive from a SignalR connection needs to be passed to a specific job context, but I'm unsure of the best approach for achieving this. ...

Issue with HighCharts: Bar columns not extending to the x-Axis when drilling up

I am encountering an issue with HighChart/HighStock that I need help with. To illustrate my problem, I have set up a JSFiddle. The problem arises when a user drills down on a bar column, causing the y-axis to shrink and consequently making the x-axis appea ...

Issue encountered while attempting to load a JSON file into an ExtJS JSONPStore due to a

After validating a json file with json.bloople.net, the file begins as follows: { "sepString": "--", When attempting to load this json file into an ExtJS JsonPStore, Chrome displays the error: Uncaught SyntaxError: Unexpected token : in line 2 What ...

Ways to divide a string into pairs of two using jQuery

I have a variable containing a string with exactly 44 characters: 02081516171821242936374750565865666871737476 I want to split it into an array in the following format: arr[0]=02 arr[1]=08 . . arr[21]=76 Can someone help me achieve this? Thank you. UP ...

Submitting a form using ajax to send form data to php without reloading the page

Could anyone please help me figure out why my code is not functioning properly? I am trying to send form data to PHP using the post method, but my PHP script is not receiving any requests. Below is the code snippet for my signup form located in signupmodal ...

What is the importance of using getters for functions involving Moment.js in vueJS and typescript?

weekOfMonth() calculates the current month and week within that month. <template> <h3>{{ weekOfMonth }}</h3> </template> <script lang="ts"> export default class HomeView extends Vue { const moment = require(& ...

Error: The "render" method is not available for the IncomingMessage object

While working on a basic application using node.js and express, everything seems to be in order except for this error that keeps popping up: res.render("aggregatedCostList",{ ^ TypeError: Object #<IncomingMessage> has no method 'render&ap ...

Is there a feature in Angular similar to Vue.js's "computed property" functionality?

After mastering Vue.js, I recently dove into Angular 4 for a new project. I've found that most things in Angular are quite similar to Vue, with the notable exception of "Computed Property". In Vue, I could easily create a computed property that would ...

Issue with AngularJS UI not refreshing after successful $.ajax call

Recently delving into AngularJS, I decided to tweak the example found at this link. In my modifications, I introduced a new payment service within the example to invoke a Json method on my server. While the backend functionality works smoothly, I encounte ...

JavaScript: AWS Amplify: Retrieving the User ID (Sub ID) Following User Registration. Post Registration, Not to Be Confused with Sign In

Currently, I am utilizing the authentication module from AWS Amplify. One question that has been on my mind is how to obtain the userID once a user signs up. While it is possible to retrieve the ID after a user signs in, I am specifically interested in re ...

Show or hide a div in Vuejs based on checkbox selection

I've been attempting to toggle the visibility of a container div using Vuejs with no success. I've tried two different methods, but neither seem to work for me. Here is Method 1: <body> <div class="checkbox" id = "selector"& ...

Incorporating Redis within an Express route

My goal is to store a value in a specific key in one route: /api/foo?redisKey="1" (setting value for the key id=1) Then, in another route, I want to retrieve the value: /api/bar?redisKey="1" (getting value for key id=1) Since redis operates asynchronou ...

Guide to successfully redirecting to a new page post login, along with sending a token as a handler to middleware using the express framework

My application utilizes nextJS, express JS, and JWT. I have created two pages - a login page and an admin page where the latter is protected and only accessible after verifying the token using JWT. My goal is to redirect users to the admin page immediately ...

Encountering difficulties in applying a dynamic aria-label to the md-datepicker component

I am currently utilizing the md-datepicker feature in my project. You can check out how it works here: https://material.angularjs.org/latest/demo/datepicker However, I am facing an issue where I am unable to dynamically add a value to the aria-label attri ...

trouble encountered while parsing JSON information using JavaScript

[ [ { "Id": 1234, "PersonId": 1, "Message": "hiii", "Image": "5_201309091104109.jpg", "Likes": 7, "Status": 1, "OtherId": 3, "Friends": 0 } ], [ { "Id": 201309091100159, "PersonI ...

Webpack has successfully built the production version of your ReactJS application. Upon review, it appears that a minified version of the development build of React is being used

Currently, I am implementing Reactjs in an application and the time has come to prepare it for production. In my package.json file, you can see that there is a "pack:prod" command which utilizes webpack along with a specific webpack.config.js file to build ...

Make sure that a specific script is loaded prior to another script

I'm struggling to understand how scripts are loaded on a page. I have jQuery plugins that rely on other scripts. Specifically, I am using the timeago jQuery plugin. I have loaded these scripts in the head in the following order: <script src="< ...

Submitting a form and using Ajax to upload an image

Is there a way to submit an image file to php using ajax without assigning the file to a variable with onchange event? I've tried triggering the request on submit click, but keep getting the error message: "cannot read property 0 of undefined." <ht ...