0
votes

I am working with NGRX (State Management) in angular 11.

I am showing a tenant list on component load. Using NGRX effect and in effect i am requesting http call through service.

This is my effect

@Injectable()
export class TenantsListEffects {
constructor(private actions$: Actions, private tenantListService: 
TenantAdministrationService) { }


loadTenants$ = createEffect(() => this.actions$.pipe(
ofType(TenantsListActions.TenantsListActionTypes.LoadTenantsLists),

switchMap(
  
  ((action) => this.tenantListService.getAllTenantsUsingGET().pipe(

  map(tenants => { return new TenantsListActions.LoadTenantsListsSuccess({ 
  data: tenants }) }),
    catchError(err => of(new TenantsListActions.LoadTenantsListsFailure({ 
  error: err })))
    )
    )
   ))
   )
  }

This is my tenantList.reducer.ts

    export const tenantsListFeatureKey = 'tenantsListState';


    export interface tenantsListState {
     tenants: DisplayNameToTenantMappingResponse[],
     loading: boolean,
     error: string
    }

     export const initialState: tenantsListState = {
  tenants: [],
  loading: false,
  error: ''
};


export function reducer(state = initialState, action: TenantsListActions): tenantsListState {
  switch (action.type) {
    case TenantsListActionTypes.LoadTenantsLists:
      return {
        ...state,
        loading: true
      }
    case TenantsListActionTypes.LoadTenantsListsSuccess:
      return {
        ...state,
        tenants: action.payload.data,
        loading:false,
        error: null
      }
    case TenantsListActionTypes.LoadTenantsListsFailure:
      return {
        ...state,
        error: action.payload.error,
        loading: false
      }

    default:
      return state;
  }
}

This is my selector

const getTenantsListState = createFeatureSelector<tenantsListState>('tenantsListState');

export const getTenants = createSelector(
    getTenantsListState,
    state => state.tenants
)

export const getError = createSelector(
    getTenantsListState,
    state => state.error
)

This is my service

@Injectable({
providedIn: 'root'
})
export class TenantAdministrationService {
public basePath: string ='';
constructor(private basePathService: BasePathService,private http: 
HttpClient) {
this.basePath = this.basePathService.selectEnv();
}

public 
getAllTenantsUsingGET():Observable<DisplayNameToTenantMappingResponse[]>{
let test =  this.http.get<Array<DisplayNameToTenantMappingResponse>> 
(`${this.basePath}/admin/tenant`);
console.log('get list ', test);

return test
}

The problem is

When i first called the service it retunes nothing and so it didn't store any thing in my ngrx store. But after 2 to 3 second it returns tenant list and stored in the store as a state.

i Tried to make async function to my service call method but it cause error in Effect.

So could some one help me how to handle this ....

enter image description here

2
Please add real code, screenshots of code is no code.Roy
hi I edited with real code.Raza Sultan

2 Answers

0
votes

It looks like you have things set up right, but I see an extra paren ( after switchMap. Like this it should work.

loadTenants$ = createEffect(() => this.actions$.pipe(
  ofType(TenantsListActions.TenantsListActionTypes.LoadTenantsLists),
  switchMap(action => this.tenantListService.getAllTenantsUsingGET().pipe(
    map(tenants => new TenantsListActions.LoadTenantsListsSuccess({ data: tenants }),
    catchError(err => of(new TenantsListActions.LoadTenantsListsFailure({ 
  error: err })))
  )
);

Keep in mind, your reducer needs to add the entities to state before your store selector will emit them.

const reducer = createReducer(
  initialState,
  on(TenantsListActions.LoadTenantsListsSuccess, (state, { data }) => featureAdapter.setAll(data, {
    ...state,
    isLoading: false,
    error: null,
  })),
  ...
);

Above I'm using an entity adapter to add the entities to state.

0
votes

I solved the problem i used the state property loading and used it as an observable in my component. `

export interface tenantsListState {
     tenants: DisplayNameToTenantMappingResponse[],
     loading: boolean,
     error: string
    }

`

During the http call this becomes loading = true; and it triggered a spinner which stop the component loading until the http call is return back.