Im trying to set up NgRx Data with a service that overrides the EntityData getAll() function, so that i can call an API. but nothing happens when i call EntityService.getAll()
entity-metadata.ts : standard definition for the EntityMetadataMap where i defined one entity named PageLoadData
import { EntityMetadataMap } from '@ngrx/data';
export const entityMetadata : EntityMetadataMap = {
PageLoadData: {
entityDispatcherOptions: {
optimisticUpdate: true
}
}
}
My AppModule.ts
import { AppResolver } from './app.resolver';
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { EntityDataModule, EntityDataService } from '@ngrx/data';
import { StoreModule } from '@ngrx/store';
import { AboutUsComponent } from './about-us/about-us.component';
import { TryAtHomeComponent } from './try-at-home/try-at-home.component';
import { ContactComponent } from './contact/contact.component';
import { DesignersComponent } from './designers/designers.component';
import { PolicyComponent } from './policy/policy.component';
import { HowItWorksComponent } from './how-it-works/how-it-works.component';
import { FooterComponent } from './footer/footer.component';
import { GiftCardComponent } from './gift-card/gift-card.component';
import { HeaderComponent } from './header/header.component';
import { HomeComponent } from './home/home.component';
import { EffectsModule } from '@ngrx/effects';
import { HttpClientModule } from '@angular/common/http';
import { StoreDevtoolsModule } from '@ngrx/store-devtools';
import { environment } from '../environments/environment';
import { PageLoadDataDataService } from './services/page-load-data.service';
import { PageLoadDataEntityService } from './services/page-load-entity.service';
import { entityMetadata } from './entity-metadata';
@NgModule({
declarations: [
AppComponent,
AboutUsComponent,
TryAtHomeComponent,
ContactComponent,
DesignersComponent,
PolicyComponent,
HowItWorksComponent,
FooterComponent,
GiftCardComponent,
HeaderComponent,
HomeComponent
],
imports: [
BrowserModule,
AppRoutingModule,
HttpClientModule,
EntityDataModule.forRoot({
entityMetadata: entityMetadata
}),
StoreModule.forRoot({}),
EffectsModule.forRoot([]),
StoreDevtoolsModule.instrument({maxAge: 25, logOnly: environment.production}),
],
providers: [PageLoadDataDataService, AppResolver, PageLoadDataEntityService],
bootstrap: [AppComponent]
})
export class AppModule {
constructor(
entityDataService: EntityDataService,
pageLoadDataService : PageLoadDataDataService,
) {
entityDataService.registerService('PageLoadData', pageLoadDataService); // <-- register it
}
}
page-load-entity-service.ts : i followed NgRx Data's standard documentation and created a service like below:
import { Injectable } from "@angular/core";
import { EntityCollectionServiceBase, EntityCollectionServiceElementsFactory } from "@ngrx/data";
import {PageLoadData } from '../user/model/user.model';
@Injectable({ providedIn: 'root' })
export class PageLoadDataEntityService extends EntityCollectionServiceBase<PageLoadData> {
constructor(serviceElementsFactory: EntityCollectionServiceElementsFactory) {
super('PageLoadData', serviceElementsFactory)
}
}
page-load-data.service.ts : created this service to override the getAll functionality of the DefaultDataService
import { PageLoadData } from './../user/model/user.model';
import { HttpClient } from '@angular/common/http';
import { Injectable } from "@angular/core";
import { DefaultDataService, HttpUrlGenerator, Logger } from "@ngrx/data";
import { Observable } from 'rxjs';
import {map} from 'rxjs/operators'
@Injectable({ providedIn: 'root' })
export class PageLoadDataDataService extends DefaultDataService<PageLoadData> {
constructor(http: HttpClient, httpUrl : HttpUrlGenerator, logger: Logger) {
super('PageLoadData' , http, httpUrl);
logger.log('in PLD Data Service');
//if i subscribe here to getAll api works fine the issue is somewhere else in the set up
}
getAll(): Observable<PageLoadData[]> {
return this.http.get<PageLoadData[]>('https://staging-api.designer-24.com/page/home?storeId=1')
}
}
app.resolver.ts : Im using a resolver to call the getAll when the EntityService is loading
import { Injectable } from "@angular/core";
import { Resolve, RouterStateSnapshot, ActivatedRouteSnapshot } from "@angular/router";
import { Observable } from "rxjs";
import { tap, filter, first } from "rxjs/operators";
import { PageLoadDataEntityService } from './services/page-load-entity.service';
@Injectable()
export class AppResolver implements Resolve<boolean> {
constructor(private pageLoadService: PageLoadDataEntityService) {}
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) : Observable<boolean> {
return this.pageLoadService.loaded$.pipe(
tap(loaded => {
console.log(loaded)
if(!loaded) {
console.log('calling get all');
this.pageLoadService.getAll();
}
}),
filter(loaded => !!loaded),
first()
)
}
}
app.routing.module.ts
import { AppComponent } from './app.component';
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { AppResolver } from './app.resolver';
const routes: Routes = [
{
path: '',
// loadChildren: () => import('./user/user.module').then(m => m.UserModule),
component: AppComponent,
resolve: {
pageLoadData: AppResolver
}
}
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
heres my app component:
import { PageLoadDataEntityService } from './services/page-load-entity.service';
import { Component } from '@angular/core';
import { Observable } from 'rxjs';
import { User, PageLoadData, HomeData } from './user/model/user.model';
import { map } from 'rxjs/operators';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.less']
})
export class AppComponent {
title = 'd24-web';
data$: Observable<PageLoadData[]>;
constructor(private userEntity : PageLoadDataEntityService) {
this.data$ = userEntity.entities$.pipe(
map(data => {
console.log(data);
return data
})
);
}
}
app component html
<span *ngIf="(data$ | async) as data" >{{data}}</span>
<router-outlet></router-outlet>
Here is the redux inspector:
screenshot of redux events
No API call and no Error is triggered even if i try to subscribe from within the resolver. I don't understand why. But in the redux inspector the getAll is triggered but its gray. not sure what that means
github link is here: https://github.com/rmoubayed/ngrx-data-test-env if anyone would like to clone and try it.
I found the solution to this mess. Everything in my setup is LEGAL and NOT wrongly implemented in any way.
As it turns out I needed to load the StoreModule & Effects BEFORE the EntityDataModule!
imports: [
BrowserModule,
AppRoutingModule,
HttpClientModule,
// EntityDataModule.forRoot({ // removed it from here
// entityMetadata: entityMetadata
// }),
StoreModule.forRoot({}),
StoreDevtoolsModule.instrument({maxAge: 25, logOnly: environment.production}),
EffectsModule.forRoot([]),
EntityDataModule.forRoot({ // and put it here
entityMetadata: entityMetadata
}),
],
After that everything worked normally again! Literal NEEDLE in a HAYSTACK :)
Hope this helps anyone else who faces the same issue :D
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With