Angular 服务注入问题:@Injectable 不起作用但提供程序可以
Angular Service Injection Issue: @Injectable Doesn't Work but Providers Does
我通过 SO 进行了扫描,但没有找到任何与我看似奇怪的问题相关的信息。我将首先复制我的一些代码以提供上下文:
我的服务:
import { Injectable } from '@angular/core';
import { MyModule } from './my.module';
@Injectable({
providedIn: MyModule,
})
export class ApiService {
// router: Router;
constructor() {
// this.router = MyModule.injector.get(Router);
}
... Some methods ...
}
我的模块:
import { NgModule, Injector } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterModule } from '@angular/router';
import { ConnectionsListComponent } from './connections-list/connections-list.component';
import { StoreModule } from '@ngrx/store';
import * as fromMy from './reducers';
import { routes } from './routes';
... component imports ...
@NgModule({
imports: [
CommonModule,
RouterModule.forChild(routes),
StoreModule.forFeature('my', fromMy.reducers),
],
declarations: [ConnectionsListComponent, MyShellComponentComponent, DashboardContainerComponent, DashboardElementComponent, DashboardElementInfoItemComponent],
// providers: [ApiService]
})
export class MyModule {
constructor() {
}
}
我的组件:
import { Component, OnInit, Input } from '@angular/core';
import { AttributeArrayHelperService } from '../attribute-array-helper.service';
import { ApiService } from '../api.service';
.. some interfaces ...
@Component({
selector: 'vz-dashboard-element',
templateUrl: './dashboard-element.component.html',
styleUrls: ['./dashboard-element.component.scss']
})
export class DashboardElementComponent implements OnInit {
@Input() element: ElementInterface;
@Input() erpType: String;
equipmentAttributes: Object[] = []
workOrderAttributes: Object[] = [
];
constructor(private apiService: ApiService) {
}
ngOnInit() {
const helper = new AttributeArrayHelperService();
console.log(this.element);
const lookupValues = helper.parseObjectArrayFor(this.element.Attributes, ['1', '2', '3']);
console.log(lookupValues);
const showValues = helper.parseArrayNames(lookupValues);
console.log(showValues);
console.log(this.apiService);
console.log(this.apiService.getDashboardEntityInformation('4', '5', '6'));
showValues.push();
this.equipmentAttributes = showValues;
}
}
好的,现在我的问题就在这里:当我尝试使用上面的 @Injectable 并声明模块时,我在浏览器中收到以下错误但没有 TS 编译错误(虽然有一个循环参考警告):
DashboardContainerComponent.html:2 ERROR Error:
StaticInjectorError(AppModule)[DashboardElementComponent ->
ApiService]: StaticInjectorError(Platform:
core)[DashboardElementComponent -> ApiService]:
NullInjectorError: No provider for ApiService!
当我将它更改为使用@Injectable() 并取消注释我的提供者时,它似乎很喜欢它并且一切都很好。我只是好奇这是为什么?通过阅读 6.1 的 Angular 文档,这似乎符合需要。
有关更多信息,这都在一个子模块中,服务应该与该模块隔离。在这一点上,我只是对我所缺少的东西感到困惑,作为我办公室中为数不多的 JS 人员之一,并且唯一使用 Angular,我没有第二只眼睛来帮助我找出我缺少的东西。
非常感谢您为此提供的任何帮助,因为这几天一直困扰着我。提前致谢,
史蒂夫
编辑:另一件需要注意的事情是,这是一个从 5 升级到 6 的应用程序。我按照指南进行操作,一切正常,所以它可能来自升级?
所以在进一步研究这个问题和功能之后,我发现我不是唯一遇到这个问题的人,这似乎是对文档的误解。正如此处所引用的:GitHub Angular CLI Issue 10170 我的处理方式是错误的,尽管有关该功能的文档似乎另有说明。
本质上,它正在创建一个导入循环,而 TS 正在尽其所能防止此类问题的发生。现在推荐使用 @Injectable()
的方法是使用 { providedIn: 'root' }
,这使得可注入服务在应用程序的根级别可用。也就是说,如果它在多个模块或根模块中使用,它似乎只在顶层捆绑。如果该服务仅在单个子模块中使用,它将与该子模块捆绑在一起。
我的解决方案是改为
@Injectable({
providedIn: 'root',
})
用于我的新服务,其余的我保留在各自模块的模块定义的 providers
数组中。至少在 providers
不再受支持之前,这一切都可以很好地协同工作,那时我会将它们全部转换为这种新格式。
我通过 SO 进行了扫描,但没有找到任何与我看似奇怪的问题相关的信息。我将首先复制我的一些代码以提供上下文:
我的服务:
import { Injectable } from '@angular/core';
import { MyModule } from './my.module';
@Injectable({
providedIn: MyModule,
})
export class ApiService {
// router: Router;
constructor() {
// this.router = MyModule.injector.get(Router);
}
... Some methods ...
}
我的模块:
import { NgModule, Injector } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterModule } from '@angular/router';
import { ConnectionsListComponent } from './connections-list/connections-list.component';
import { StoreModule } from '@ngrx/store';
import * as fromMy from './reducers';
import { routes } from './routes';
... component imports ...
@NgModule({
imports: [
CommonModule,
RouterModule.forChild(routes),
StoreModule.forFeature('my', fromMy.reducers),
],
declarations: [ConnectionsListComponent, MyShellComponentComponent, DashboardContainerComponent, DashboardElementComponent, DashboardElementInfoItemComponent],
// providers: [ApiService]
})
export class MyModule {
constructor() {
}
}
我的组件:
import { Component, OnInit, Input } from '@angular/core';
import { AttributeArrayHelperService } from '../attribute-array-helper.service';
import { ApiService } from '../api.service';
.. some interfaces ...
@Component({
selector: 'vz-dashboard-element',
templateUrl: './dashboard-element.component.html',
styleUrls: ['./dashboard-element.component.scss']
})
export class DashboardElementComponent implements OnInit {
@Input() element: ElementInterface;
@Input() erpType: String;
equipmentAttributes: Object[] = []
workOrderAttributes: Object[] = [
];
constructor(private apiService: ApiService) {
}
ngOnInit() {
const helper = new AttributeArrayHelperService();
console.log(this.element);
const lookupValues = helper.parseObjectArrayFor(this.element.Attributes, ['1', '2', '3']);
console.log(lookupValues);
const showValues = helper.parseArrayNames(lookupValues);
console.log(showValues);
console.log(this.apiService);
console.log(this.apiService.getDashboardEntityInformation('4', '5', '6'));
showValues.push();
this.equipmentAttributes = showValues;
}
}
好的,现在我的问题就在这里:当我尝试使用上面的 @Injectable 并声明模块时,我在浏览器中收到以下错误但没有 TS 编译错误(虽然有一个循环参考警告):
DashboardContainerComponent.html:2 ERROR Error: StaticInjectorError(AppModule)[DashboardElementComponent -> ApiService]: StaticInjectorError(Platform: core)[DashboardElementComponent -> ApiService]: NullInjectorError: No provider for ApiService!
当我将它更改为使用@Injectable() 并取消注释我的提供者时,它似乎很喜欢它并且一切都很好。我只是好奇这是为什么?通过阅读 6.1 的 Angular 文档,这似乎符合需要。
有关更多信息,这都在一个子模块中,服务应该与该模块隔离。在这一点上,我只是对我所缺少的东西感到困惑,作为我办公室中为数不多的 JS 人员之一,并且唯一使用 Angular,我没有第二只眼睛来帮助我找出我缺少的东西。
非常感谢您为此提供的任何帮助,因为这几天一直困扰着我。提前致谢,
史蒂夫
编辑:另一件需要注意的事情是,这是一个从 5 升级到 6 的应用程序。我按照指南进行操作,一切正常,所以它可能来自升级?
所以在进一步研究这个问题和功能之后,我发现我不是唯一遇到这个问题的人,这似乎是对文档的误解。正如此处所引用的:GitHub Angular CLI Issue 10170 我的处理方式是错误的,尽管有关该功能的文档似乎另有说明。
本质上,它正在创建一个导入循环,而 TS 正在尽其所能防止此类问题的发生。现在推荐使用 @Injectable()
的方法是使用 { providedIn: 'root' }
,这使得可注入服务在应用程序的根级别可用。也就是说,如果它在多个模块或根模块中使用,它似乎只在顶层捆绑。如果该服务仅在单个子模块中使用,它将与该子模块捆绑在一起。
我的解决方案是改为
@Injectable({
providedIn: 'root',
})
用于我的新服务,其余的我保留在各自模块的模块定义的 providers
数组中。至少在 providers
不再受支持之前,这一切都可以很好地协同工作,那时我会将它们全部转换为这种新格式。