I tried to implement Ngrx into my Angular Application, but sadly haven't been able to retrieve any data. Any help is appreciated!
What I'm trying to do in the property.component.ts is to get all the data when the component gets instantiated and just display the data in the property.component.html
.
property.component.ts
import {Component, OnInit} from '@angular/core';
import {select, Store} from '@ngrx/store';
import {Router} from '@angular/router';
@Component({
selector: 'app-property',
templateUrl: './property.component.html',
styleUrls: ['./property.component.css']
})
export class PropertyComponent implements OnInit {
properties$ = this._store.pipe(select('properties'));
constructor(private _store: Store<any>, private _router: Router) {}
ngOnInit() {
this._store.dispatch({
type: '[Property] Get Properties'
});
console.log(this.properties$);
}
navigateToProperty(id: number) {
this._router.navigate(['property', id]);
}
}
property.component.html
<p>test</p>
<p>{{properties$ | async}}</p>
property.service.ts
import { Injectable } from '@angular/core';
import {HttpClient, HttpHeaders} from '@angular/common/http';
import { Observable } from 'rxjs';
import {PropertyModel} from '../models/property.model';
@Injectable({
providedIn: 'root'
})
export class PropertyService {
propertiesUrl = 'someapi';
private httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/json'
})
};
constructor(private http: HttpClient) { }
getProperties(): Observable<PropertyModel[]> {
return this.http.get<PropertyModel[]>(this.propertiesUrl, this.httpOptions);
}
}
property.actions.ts
import { Action } from '@ngrx/store';
import {PropertyModel} from '../../models/property.model';
export const GET_PROPERTIES = '[Property] Get Properties';
export const GET_PROPERTIES_SUCCESS = '[Property] Get Properties Success';
export const SEARCH_PROPERTY = '[Property] Get Property';
export const SEARCH_PROPERTY_SUCCESS = '[Property] Get Property Success';
export class GetProperties implements Action {
public readonly type = GET_PROPERTIES;
constructor(public retrievedProperties: PropertyModel[]) {}
}
export class GetPropertiesSuccess implements Action {
public readonly type = GET_PROPERTIES_SUCCESS;
constructor(public retrievedProperties: PropertyModel[]) {}
}
export class GetProperty implements Action {
public readonly type = SEARCH_PROPERTY;
constructor(public searchId: string) {}
}
export type PropertyActions = GetProperties | GetPropertiesSuccess | GetProperty;
property.effects.ts
import {Injectable} from '@angular/core';
import {Actions, Effect, ofType} from '@ngrx/effects';
import {GET_PROPERTIES, PropertyActions} from '../actions/property.actions';
import {PropertyService} from '../../services/property.service';
import {mapTo} from 'rxjs/operators';
@Injectable()
export class PropertyEffects {
@Effect()
getProperties$ = this.actions$.pipe(
ofType<PropertyActions>(GET_PROPERTIES),
mapTo(this.propertyService.getProperties())
);
constructor(private actions$: Actions, private propertyService: PropertyService) {}
}
and finally my property.reducers.ts
import {GET_PROPERTIES, GET_PROPERTIES_SUCCESS, PropertyActions} from '../actions/property.actions';
import {PropertyModel} from '../../models/property.model';
export function propertyReducer(properties: PropertyModel[] = [], action: PropertyActions): PropertyModel[] {
switch (action.type) {
case GET_PROPERTIES: {
return [...action.retrievedProperties];
}
default: {
return properties;
}
}
}
app.module.ts
import {BrowserModule} from '@angular/platform-browser';
import {NgModule} from '@angular/core';
import {AppComponent} from './app.component';
import {CustomerComponent} from './customer/customer.component';
import {HttpClientModule} from '@angular/common/http';
import {CustomMaterialModule} from './custom.material.module';
import {RouterModule, Routes} from '@angular/router';
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
import {StoreModule} from '@ngrx/store';
import {PropertyComponent} from './property/property.component';
import {propertyReducer} from './store/reducers/property.reducers';
const appRoutes: Routes = [
{
path: 'customers',
component: CustomerComponent,
data: {title: 'Customer List'}
},
{
path: 'property',
component: PropertyComponent,
data: {title: 'Property List'}
},
{
path: '', // General redirect
component: CustomerComponent,
pathMatch: 'full'
}
];
@NgModule({
declarations: [
AppComponent,
CustomerComponent,
PropertyComponent
],
imports: [
BrowserModule,
RouterModule.forRoot(appRoutes),
HttpClientModule,
BrowserAnimationsModule,
CustomMaterialModule,
StoreModule.forRoot(propertyReducer)
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule {}
Working stackblitz example
Don't forget to dispatch success and error actions and to reduce them.
Also change mapTo
to switchMapTo
@Effect()
getProperties$ = this.actions$.pipe(
ofType<PropertyActions>(GET_PROPERTIES),
switchMapTo(this.propertyService.getProperties().pipe(
map(props => new GetPropertiesSuccess(props)),
// catch error here
// catchError(error => of(new GetPropertiesError(error))),
),
),
);
In your reducer, listen to correct type
case GET_PROPERTIES_SUCCESS: {
return [...action.retrievedProperties];
}
For clarity remove retrievedProperties
from GetProperties
- the action does not have any retrieved props. The success action should be used to pass them.
In your app module change the reducer setup and don't forget to import the effects:
imports: [
BrowserModule,
RouterModule.forRoot(appRoutes),
HttpClientModule,
BrowserAnimationsModule,
// change this
StoreModule.forRoot({properties: propertyReducer}),
// this is needed
EffectsModule.forRoot([PropertyEffects])
],
Optional: In your PropertyComponent
change the the dispatched action to the instance of the GetProperties
class. That's how it should be used.
this._store.dispatch(new GetProperties());
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