I have a problem where my application giving an error: No Provider for Data Service.
This typically happens when you have forgotten to list your service as a provider either in the app module or the feature module, however in my case I have set it as a provider.
My application is built on Angular 9 with Ngrx statement management and interacting with a Firestore DB.
I am not doing a simple provider as i am trying to tie the service into ngrx/data which is really designed to work with a Rest API which firebase is not.
Error in browser * NullInjectorError: R3InjectorError(ProductsModule)[ProductsResolver -> DataService -> DataService -> DataService -> DataService -> DataService]: NullInjectorError: No provider for DataService! *
Code is below if anyone can see something obvious or suggest something to point me in the right direction.
Product Feature Module I am setting the Data Service as a provider in the feature module - I have also tried moving up to App Module but still getting the same error
import { ProductsResolver } from "./services/products.resolver";
import { ProductsListComponent } from "./products-list/products-list.component";
import { ProductComponent } from "./product/product.component";
import { DataService } from "./services/generic-data-service";
import { Product } from "@shared/models/product.model";
import { NgModule } from "@angular/core";
import { RouterModule, Routes } from "@angular/router";
import {
EntityMetadataMap,
EntityCollectionServiceElementsFactory
} from "@ngrx/data";
import { FirestoreService } from "@core/services/firestore.service";
const routes: Routes = [
{
path: "products-list",
component: ProductsListComponent,
resolve: {
products: ProductsResolver
}
}
];
@NgModule({
declarations: [ProductsListComponent, ProductComponent],
imports: [
RouterModule.forChild(routes)
],
providers: [
{
provide: "ProductsService",
useFactory: (
firestoreService: FirestoreService,
elementsFactory: EntityCollectionServiceElementsFactory
) => {
return new DataService<Product>(
Product,
firestoreService,
elementsFactory
);
},
deps: [FirestoreService, EntityCollectionServiceElementsFactory],
multi: false
},
ProductsResolver
]
})
export class ProductsModule {}
Product List Component I am injecting the service in the component but get an error in the browser saying there is no provider.
import { DataService } from "../services/generic-data-service";
import { Product } from "@shared/models/product.model";
import {
ChangeDetectionStrategy,
Component,
OnInit,
ViewEncapsulation,
Inject
} from "@angular/core";
import { Observable } from "rxjs";
@Component({
selector: "fw-products",
templateUrl: "./products-list.component.html",
styleUrls: ["./products-list.component.scss"],
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush
})
export class ProductsListComponent implements OnInit {
products$: Observable<any>;
constructor(
@Inject("ProductsService")
private _dataService: DataService<Product>
) {}
ngOnInit(): void {
this._dataService.getMyEntities().subscribe(data => {
this._dataService.clearCache();
this._dataService.upsertManyInCache(data);
this._dataService.entities$.subscribe(
data => console.log(data)
);
});
}
}
Data Service
import { FirestoreService } from "@core/services/firestore.service";
import { Product } from "@shared/models/product.model";
import { BaseModel } from "@shared/models/entity-base.model";
import { Injectable } from "@angular/core";
import {
EntityCollectionServiceBase,
EntityCollectionServiceElementsFactory
} from "@ngrx/data";
import { Observable } from "rxjs";
Injectable();
export class DataService<
T extends BaseModel
> extends EntityCollectionServiceBase<T> {
x: string;
constructor(
cls: typeof Product,
public firestoreService: FirestoreService,
elementsFactory: EntityCollectionServiceElementsFactory
) {
super(cls.entityName, elementsFactory);
this.x = cls.firebasePath;
}
getMyEntities(): Observable<any[]> {
return this.firestoreService.getAll(this.x);
}
createEntity(data: any): void {
this.firestoreService.createDoc(`${this.x}/`, data);
}
updateEntity(data: any): void {
this.firestoreService.updateDoc(`${this.x}/`, data);
}
deleteEntity(data: any): void {
this.firestoreService.deleteDoc(`${this.x}/`, data);
}
}
Products Resolver
import { Injectable } from "@angular/core";
import {
Resolve,
ActivatedRouteSnapshot,
RouterStateSnapshot
} from "@angular/router";
import { Observable } from "rxjs";
import { map, tap, filter, first } from "rxjs/operators";
import { DataService } from './generic-data-service';
import { Product } from '@shared/models/product.model';
@Injectable()
export class ProductsResolver implements Resolve<boolean> {
constructor(private _productsService: DataService<Product>) {}
resolve(
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot
): Observable<boolean> {
return this._productsService.loaded$.pipe(
tap(loaded => {
if (!loaded) {
this._productsService.getAll();
}
}),
filter(loaded => !!loaded),
first()
);
}
}
@Injectable()
on yourDataService
not justInjectable()
– Andrew Allen