Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Error when accessing static properties when services include each other

When running the following code as-is, it get this error:

Uncaught TypeError: Cannot read property 'TYPE_CAMPAIGN' of undefined

Plunker Example

entity.service.ts

import {Injectable} from '@angular/core';
import {CampaignService} from './campaign/campaign.service';
import {TagService} from './tag/tag.service';

@Injectable()
export class EntityService {
  static TYPES = [
    CampaignService.TYPE_CAMPAIGN,
    TagService.TYPE_TAG
  ];
}

campaign.service.ts

import {Injectable} from '@angular/core';
import {EntityService} from '../entity.service';

@Injectable()
export class CampaignService {
  static TYPE_CAMPAIGN = 'campaign';

  constructor(private entityService: EntityService) {}

  public getTypes() {
    return EntityService.TYPES;
  }
}

tag.service.ts

import {Injectable} from '@angular/core';
import {EntityService} from '../entity.service';

@Injectable()
export class TagService {
  static TYPE_TAG = 'tag';

  constructor(private entityService: EntityService) {}
}

However, when I remove the constructor from campaign.service.ts, the code works without issue. Why does the error occur, and how do I access static properties when the constructor is included?

Update 1: After testing using Angular's Injector to offset when classes are loaded, I find that I still have an issue accessing static properties of EntityService inside methods of CampaignService. I've also found that adding private entityService: EntityService in campaign.service.ts causes the issue.

Update 2: The issue is caused by the order of import statements in the Module that is providing the services (I recently alphabetized my import statements).

app.module.ts

import {CampaignService} from './campaign/campaign.service';
import {EntityService} from '../entity.service';
import {TagService} from './tag/tag.service';

@NgModule({
  providers: [
    CampaignService,
    EntityService,
    TagService
  ]
});

When the import statement for entity.service.ts is moved before campaign.service.ts, both CampaignService and TagService are able to work without issue.

Update 3: It looks like the issue is version specific. Here is the example of the issue happening in the version I am currently using: Example

If you switch the import statements in src/app.component.ts while watching the console, then you will see the issue at hand.

like image 713
Myzaree Avatar asked May 02 '26 16:05

Myzaree


1 Answers

It may be the injector decides there's a circular reference. Looking at the code, I would not expect it since only one service has a constructor. However, the behavior you describe points to this.

You can try injecting the injector and delaying the injection process by a tick.
See Angular2: 2 services depending on each other

@Injectable()
export class CampaignService {
  static TYPE_CAMPAIGN = 'campaign';
  private entityService;

  constructor(injector: Injector) {
    setTimeout(() => this.entityService = injector.get(EntityService));
  }
}

Using EntityService.TYPES inside campaign.service.ts

Hopefully this covers your use-case. Here's my StackBlitz

campaign.service.ts

import {Injectable, Injector} from '@angular/core';
import {EntityService} from './entity.service';

@Injectable()
export class CampaignService {
  static TYPE_CAMPAIGN = 'campaign';
  private entityService;
  types = EntityService.TYPES;

  constructor(private injector: Injector) {
    setTimeout( () => this.entityService = injector.get(EntityService) );
  }
}

app.component.ts

import { Component } from '@angular/core';
import {EntityService} from './entity.service';
import {CampaignService} from './campaign.service';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent  {
  name = 'Angular 5';
  types = EntityService.TYPES;

  constructor(
    private entityService: EntityService, 
    private campaignService: CampaignService
  ) { }
}

app.component.html

<hello name="{{ name }}"></hello>
<p>
  Start editing to see some magic happen :)
</p>
<div> Types from EntityService {{ types }} </div>
<div> Types from campaignService {{ campaignService.types }} </div>
like image 75
Richard Matsen Avatar answered May 04 '26 07:05

Richard Matsen



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!