简体   繁体   中英

Angular 7 - Accessing to service returns undefined in observable

I'm working with a service that implements a global service called AppService which stores some global app configurations.

To begin with my question, I will post here some of my codes:

app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule, Injector, APP_INITIALIZER } from '@angular/core';
import { AppService } from './app.service';

...

export function appLoadConfig(appService: AppService) {
  return () => appService.loadConfig();
}

@NgModule({
  imports: [
    BrowserModule,
    CoreModule,
    ...
  ],
  declarations: [
    AppComponent,
  ],
  providers: [
    {
      provide: APP_INITIALIZER,
      useFactory: appLoadConfig,
      deps: [ AppService ],
      multi: true
    }
  ],
  bootstrap: [ AppComponent ]
})
export class AppModule {}

app.service.ts

import { Injectable, ... } from '@angular/core';

...

@Injectable({
  providedIn: 'root'
})
export class AppService {

  loadConfig(): Promise<any> { ... }

}

file.service.ts

import { Injectable } from '@angular/core';
import { AppService } from '../../app.service';
...

@Injectable()
export class FileService {

  filesChange: BehaviorSubject<FileNode[]> = new BehaviorSubject<FileNode[]>([]);

  constructor(
    private appService: AppService,
    private httpClient: HttpClient) { }

  changeListType(types: string[]) {
    this._getAllFiles();
  }

  private _getAllFiles() {
    this.httpClient.get<any>(`${this.appService.config.api}/api/files/`)
        .subscribe(this._publishData);
  }

  private _publishData(data: FileNode[]) {
    let nodeData: FileNode[] = [];
    data.forEach((n: any) => {
      const node = new FileNode(n);
      node.fullPath = `${this.appService.config.api}/uploads/${node.uri}`;
      nodeData.push(node);
    });
    this.filesChange.next(nodeData);
  }
}

When in a component I call the changeListType method from file.service , it retrieves the data, but the _publishData method shows that this.appService , used to build the node.fullPath , is undefined. If I change the call in the _getAllFiles method subscriber to this one:

this.httpClient.get<any>(`${this.appService.config.api}/api/files/`)
            .subscribe((data: any) => { this._publishData(data); });

The appService variable is not undefined anymore. Is this on purpose or it is a kind of bug/error related with scope variables? Or maybe I'm missing something within my code logic.

Thanks in advance.

You have got a problem with the scope of this :

In your second approach where you are not getting appService as undefined because you are referencing _publishData function from within an arrow function. Arrow functions doesn't create their own this and uses the this from it's outer scope. When _publishData function is being invoked in this case the this which it is referencing is the this of the component and not the function's this

Read more about arrow functions here .

If you are not using an arrow function and want to get the correct this for the subscriber function you will need to bind the this

You need to bind the correct this to _publishData function

  private _getAllFiles() {
    this.httpClient.get<any>(`${this.appService.config.api}/api/files/`)
        .subscribe(this._publishData.bind(this));
  }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM