Home > Mobile >  Angular, function is undefined when passed to a class in model, but works if called directly
Angular, function is undefined when passed to a class in model, but works if called directly

Time:09-19

I'm trying to create a class that has a function that would start a self calling loop every 5 seconds that would check a certain server settings using http.request library and, when the setting matches the one that is defined in the calling arguments, it would emit a signal and stop calling itself. (I haven't actually gotten into writing the job itself, just to the point of trying to get the setup work).

The problem is that I have a method for calling the server which works if directly called from the component, but it gives the following error when the function in the model tries to use it:

ERROR TypeError: Cannot read properties of undefined (reading 'request')

This is the basic logic that I'm using:

The component:

import { Component, OnInit, EventEmitter } from '@angular/core';
import { ServerService } from '../../server.service';
import { SafePipe } from '../../_helpers/safe.pipe';
import { SharedVariables } from '../../_services/shared-variables.service';
import { ServerSettingValueObserver } from '../../_models/valueObservers.model';

@Component({
  selector: 'app-analytics',
  templateUrl: './analytics.component.html',
  styleUrls: ['./analytics.component.css']
})
export class AnalyticsComponent implements OnInit {
  analyticsUrl;
  iframeStatus = new EventEmitter();

  constructor(private server: ServerService, private sharedVariables: SharedVariables, private safe: SafePipe) { }

  ngOnInit(): void {
    this.sharedVariables.getAnalyticsUrl().subscribe((value) => {
      this.analyticsUrl = value;
    });
    var value_observer = new ServerSettingValueObserver("iframeEnabled", true, this.iframeStatus);
    value_observer.startJob(this.server.getServerSettings);
  }

  changeMatomoStatus() {
    this.server.changeMatomoStatus().then((res) => {
      console.log("changed");
    });
  }
}

This is the relevant service that is being passed to the function in the class:

  getServerSettings() {
    return this.request('GET', '/api/settings/server');
  }

And this is the model:

export class ServerSettingValueObserver{
  constructor(
    public value: string,
    public state: boolean,
    public signal: any,
  ){ }

  public startJob(job: any): void{
    console.log('job',job)
    job().then((response: any) => {
      console.log(response);
    });
  }
}

This is the output of the console.log:

job ƒ getServerSettings(){return this.request("GET","/api/settings/server")}

I think that should mean that the object that is passed to the function should be a function, but why do I get the error in this case?

Just to test things out I tried directly calling the function in the service and it worked without problem.

For this test I substituted:

var value_observer = new ServerSettingValueObserver("iframeEnabled", true, this.iframeStatus);
value_observer.startJob(this.server.getServerSettings);

With:

this.server.getServerSettings().then((response: any) => {
  console.log(response);
});

CodePudding user response:

Change this line:

    value_observer.startJob(this.server.getServerSettings)

To this:

    value_observer.startJob(() => this.server.getServerSettings())

Or this:

     value_observer.startJob(() => this.server.getServerSettings.bind(this.server))

You're getting an error because when you pass the function as an argument this way, it loses the this context, so this will be indeed undefined. To keep the correct value for this, you have to pass an arrow function (first example) or bind the value manually (second example).

  • Related