Issue with Angular 7 ngZone causing undefined error

I've been struggling to display a 3D object using three.js. Every time I attempt to start the animation loop (within ngAfterViewInit), I keep encountering the same error:

TypeError: Cannot read property 'ngZone' of undefined

In an effort to optimize CPU usage, I am utilizing ngZone to trigger requestAnimationFrame outside of Angular. Even after removing the ngZone code, I still face this error:

TypeError: Cannot read property 'animate' of undefined

All of this is happening after the necessary resources have finished loading. Just to clarify, there is no class-level variable for ngZone - it is simply called as a parameter in the constructor.

Below is the relevant code snippet:

export class ProductComponent{
//setup variables
// shirt model and texture are fetched from Firebase storage
constructor(private storage : AngularFireStorage, public ngZone: NgZone) {

        this.modelUrl = this.storage.ref('path/to/model.obj').getDownloadURL();
        this.textureUrl = this.storage.ref('path/to/texture.jpg').getDownloadURL();

        this.camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 2000);
        this.scene = new THREE.Scene();
        this.controls = new THREE.OrbitControls(this.camera,this.renderer.domElement);
        this.clock = new THREE.Clock();
        this.manager = new THREE.LoadingManager();
        this.loader = new THREE.OBJLoader(this.manager);
    }

ngAfterViewInit(){
    //setup
    this.loadResources(this.modelValue, this.texture, this.scene, this.renderer, this.container, this.animate);
 }
private loadResources(model, texture, scene, renderer, container, callback){

    this.camera.position.set(0, 0, 50);
    this.camera.lookAt(new THREE.Vector3(0, 0, 0));

    // scene

    scene.fog = new THREE.FogExp2(0xffffff, 0.0003);

    const ambientLight = new THREE.AmbientLight(0xcccccc, 0.4);
    scene.add(ambientLight);

    const pointLight = new THREE.PointLight(0xffffff, 0.8);
    this.camera.add(pointLight);
    scene.add(this.camera);

    this.loader.load(model, function (object) {
        object.traverse(function (child) {

            if (child instanceof THREE.Mesh) {

                child.material.map = texture;

                // repeat image on model
                child.material.map.wrapS = child.material.map.wrapT = THREE.RepeatWrapping;
                child.material.map.repeat.set(4, 4);

                child.material.needsUpdate = true;

            }

        });

        object.scale.set(1.5, 1, 1.5);
        scene.add(object);
        console.log('PARTS:', object.children);

        renderer.setPixelRatio(window.devicePixelRatio);
        renderer.setClearColor(scene.fog.color);
        renderer.setSize(window.innerWidth, window.innerHeight);
        container.appendChild(renderer.domElement);

        callback();
    }); //onProgress, onError
}

animate() : void {
        this.ngZone.runOutsideAngular(() => {
            requestAnimationFrame(this.animate);
        });
        this.render();
        this.update();

    }

}

Answer №1

this.triggerAnimation is executed within the function fetchData. The function call includes this.triggerAnimation as the final argument:

this.fetchData(this.dataValue, this.apiEndpoint, this.element, this.triggerAnimation);

The issue arises because this.triggerAnimation will be triggered within the responseHandler of this.dataFetcher.fetch and this responseHandler is a standard function, so this inside of triggerAnimation will not contain the required context or animation. A potential solution is to utilize an arrow function for the responseHandler of this.dataFetcher.fetch (as this.triggerAnimation will be executed within it):

private fetchData(data, endpoint, element, responseHandler) {

  this.element.style.color = 'blue';
  this.element.textContent = 'Loading...';

  // apply arrow function for responseHandler of this.dataFetcher.fetch
  this.dataFetcher.fetch(data, (result) => {

    result.forEach(function (item) {

      if (item.type === 'text') {
        element.innerHTML += `<p>${item.content}</p>`;
      }

    });

    console.log('Data Result:', result);
    responseHandler();
  });
}

Alternatively, if a standard function is preferred as the responseHandler for this.dataFetcher.fetch, the this context can be bound to responseHandler:

// store this in a variable named self,
// to enable binding
const self = this;
this.dataFetcher.fetch(data, function(result) {

  ...

  // this.triggerAnimation
  const responseHandlerWithThisBinding = responseHandler.bind(self);
  responseHandlerWithThisBinding();
}

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

Synchronizing Form Data in Angular 5: Pass and Populate Dropdowns between Components

I have developed a unique form (material dialog modal) that allows users to create an account. When the user clicks on the Register button, their created account should appear in a dropdown menu without redirecting or reloading the current page. I am facin ...

The div element is finally loading properly after multiple clicks

I need some assistance with loading dynamic divs in Angular. I have created a button that adds new divs each time it is clicked in a specific area. However, once these new divs are added, they appear incorrectly: https://i.sstatic.net/sAE6q.png After add ...

What is the method for reaching THREE.Geometry?

Is it possible to create a complex object, such as a mountain shape, without using THREE.PlaneGeometry? Can THREE.Geometry be used for this task instead? ...

Exploring the differences between Typescript decorators and class inheritance

I find myself puzzled by the concept of typescript decorators and their purpose. It is said that they 'decorate' a class by attaching metadata to it. However, I am struggling to understand how this metadata is linked to an instance of the class. ...

The 'MutableRefObject<null>' type is lacking the following properties that are present in the 'Element' type

I'm eager to implement intersection observer in my React Typescript project. (https://www.npmjs.com/package/react-intersection-observer) However, I encountered an issue with setting the root: const root = useRef(null); const { ref, inView, entry } ...

What is the best method to add data to a child array located within a nested array?

Struggling to create an array that will display data in the following format: Healthcare -- Insights driven by data for improved healthcare -- Urban Analytics Transport -- Urban Analytics Cities -- Urban Analytics I have attempted ...

send the checkbox control's model value back to the parent control in Vue3

I've implemented a wrapper control for checkboxes that closely resembles my textbox control. This approach ensures consistent validation and design throughout the application. While I was successful in getting it to work for textboxes, I encountered s ...

How can you load an HTML page in Puppeteer without any CSS, JS, fonts, or images?

My current task involves using Puppeteer to scrape data from multiple pages in a short amount of time. However, upon closer inspection, I realized that the process is not as efficient as I would like it to be. This is because I am only interested in spec ...

Resolving a persistent AngularJS 1 constant problem with Typescript

I'm currently developing an application using TypeScript and AngularJS 1, and I've encountered a problem while trying to create a constant and passing it to another class. The constant in question is as follows: module app{ export class A ...

Experimenting with a module reliant on two distinct services

I am facing an issue with a component that relies on a service to fetch data. The service also retrieves configurations from a static variable in the Configuration Service, but during Karma tests, the const variable is showing up as undefined. Although I ...

Using React.ReactNode as an argument in Storybook

This is a unique button component type that I have created import React from 'react' export type ButtonProps = { label: string; color?:'primary' | 'secondary' | 'tertiary'; size?:'mobile' | 'tabl ...

Ways to implement variable face sizes in three.js meshes

Recently, I dove into the world of three.js and started playing around with it. I've been pondering whether there's a way to add some randomness to the size of the faces in a mesh created from their existing geometries. While three.js is fantast ...

Changing the order of a list in TypeScript according to a property called 'rank'

I am currently working on a function to rearrange a list based on their rank property. Let's consider the following example: (my object also contains other properties) var array=[ {id:1,rank:2}, {id:18,rank:1}, {id:53,rank:3}, {id:3,rank:5}, {id:19,r ...

Error: Invalid character '&' after initializing create-t3-application bootstrap

After initiating a new next.js app with the command npm create t3-app@latest, I encountered an unexpected syntax error when running the app using npm run dev. The error displayed was SyntaxError: Unexpected token '??='. Additionally, my console o ...

Leverage advanced type deduction in Key Remapping

I'm puzzled by this code snippet: type Foo<T extends string> = [T] extends [infer Y] ? Y : never // works fine type Test_2<T extends Array<string>> = { [P in T[number] as Foo<"foo">]: undefined } // no issues type ...

Experimenting with PIXI.js and Jest within a React Single Page Application

I am currently working on a react application that utilizes PIXI.js and @inlet/react-pixi for animations. During testing with Jest, I encountered the following errors: Error: Uncaught [TypeError: Cannot read properties of null (reading 'stage' ...

Eliminating data type from union in Typescript

I have a specific type that I collect from various other types: type CustomType = { id: string; foo: (string | Type1)[]; bar: (string | Type2)[]; baz: string | Type3 | null; description: string | null; } I am interested in refining thi ...

three.js extra texture shade

How can I apply an additional color to a mesh with a base color using a (Voronoi) texture to determine the intensity of the color in three.js? If this is not currently possible, what is the most effective method to implement this functionality? Should I c ...

Instructions for disabling editing for a specific cell within an inline editable row in primeNG

I am currently using PrimeNG DataTable with Angular, where the rows are editable as shown in the example in the documentation: https://www.primefaces.org/primeng/#/table/edit. However, I am facing an issue where I want to exclude one cell from being editab ...

Uniform retrieval function for interaction with API

I have developed my server backend using PHP and now I am looking to establish communication between the frontend (typescript) and backend. For each of my API requests, I desire to receive a standardized response. Hence, every response from the server fol ...