Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why am I not getting any Data? Ngrx

Tags:

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 {}
like image 256
BlueScoreMan Avatar asked Mar 22 '19 14:03

BlueScoreMan


1 Answers

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());
like image 144
kvetis Avatar answered Oct 19 '22 13:10

kvetis