ngrx не поддерживает состояние - PullRequest
0 голосов
/ 06 октября 2018

Используя собственную реализацию небольшого магазина (что сработало), я пытаюсь ввести ngrx / store в угловое приложение.Версии:

"@ngrx/core": "^1.2.0",
"@ngrx/store": "^6.1.0"

Приложение представляет собой угловой интерфейс, который получает / записывает данные в базу данных через приложение Spring через http.Когда BankaccountListComponent загружается впервые, он извлекает список банковских счетов из базы данных через BankaccountService и, соответственно, весеннее приложение.BankaccountService записывает извлеченные данные в хранилище.Через наблюдаемый BankaccountListComponent подключается к хранилищу.

Однако он не получает данные.В клиенте отображается только пустое поле.Похоже, что наблюдаемое bankaccounts$ никогда не обновляется магазином.

Возможно, ошибка очевидна для вас, просто посмотрев код ниже.Если вы хотите, чтобы я создал работающее приложение, например, в jsfiddle, пожалуйста, дайте мне знать, и я сделаю это.

вывод консоли

bankaccountReducer: default action Array [] bankaccount.reducer.ts:24:6
Angular is running in the development mode. Call enableProdMode() to enable the production mode. core.js:3121
BankaccountListComponent: ngOnInit bankaccount-list.component.ts:20:4
BankaccountListComponent: leaving ngOnInit bankaccount-list.component.ts:23:4
BankaccountService: fetched 2 bankaccounts from server bankaccount.service.ts:30:6
BankaccountService: bankaccounts retrieved: Array [ {…}, {…} ] bankaccount.service.ts:33:6
bankaccountReducer: loading data: Array [ {…}, {…} ] bankaccount.reducer.ts:7:6
BankaccountService: bankaccounts dispatched
BankaccountItemComponent: got bankaccount undefined

bankaccount-list.component.html

<div class="bankaccount-list">
  <h1>Bank Accounts</h1>
  <div>
    <app-bankaccount-item *ngFor="let bankaccount of bankaccounts$ | async"
                          [bankaccount]="bankaccount">
    </app-bankaccount-item>
  </div>
</div>

bankaccount-list.component.ts

import {Component, OnDestroy, OnInit} from '@angular/core';
import {Observable} from 'rxjs/Observable';
import {BankaccountService} from '../../services/bankaccount.service';
import {Bankaccount} from '../../model/bankaccount';

@Component({
  selector: 'app-bankaccount-list',
  templateUrl: './bankaccount-list.component.html',
  styleUrls: ['./bankaccount-list.component.scss']
})
export class BankaccountListComponent implements OnInit, OnDestroy {

  bankaccounts$: Observable<Bankaccount[]>;
  bankaccountSelectedId: number;

  constructor(private bankaccountService: BankaccountService) {
  }

  ngOnInit() {
    console.log('BankaccountListComponent: ngOnInit');
    this.bankaccounts$ = this.bankaccountService.bankaccounts$;
    this.bankaccountService.getBankaccounts();
    console.log('BankaccountListComponent: leaving ngOnInit');
  }

  ngOnDestroy() {
    console.log('BankaccountListComponent: destroy');
  }
}

bankaccount-item.component.ts

import {Component, EventEmitter, Input, Output} from '@angular/core';
import {Router} from '@angular/router';
import {Bankaccount} from '../../model/bankaccount';

@Component({
  selector: 'app-bankaccount-item',
  templateUrl: './bankaccount-item.component.html',
  styleUrls: ['./bankaccount-item.component.scss']
})
export class BankaccountItemComponent {

  @Input() selected: boolean;
  @Input() bankaccount: Bankaccount;

  @Output() bankAccountSelected = new EventEmitter();
  @Output() bankAccountDeleted = new EventEmitter();

  constructor() {
    console.log('BankaccountItemComponent: got bankaccount', this.bankaccount);
  }
}

bankaccount-item.component.html

<div class="fade-in bankaccount-item" [ngClass]="{selected : selected}" (click)="select()">
  <mat-card>
    <mat-card-content>
      <div class="row">

        <div class="col1">
      <span>
        <a [routerLink]="['./edit', bankaccount.id]"
           (click)="$event.stopPropagation();">{{bankaccount.name}}</a>
      </span>
          <br>
          <span class="grey">{{bankaccount.iban | iban}}</span>
        </div>

        <div class="col2">
          <button mat-button (click)="delete(); $event.stopPropagation()">
            <mat-icon>delete_forever</mat-icon>
          </button>
        </div>

      </div>
    </mat-card-content>
  </mat-card>
</div>

bankaccount.service.ts

import {Injectable} from '@angular/core';
import {HttpClient, HttpHeaders} from '@angular/common/http';

import {Observable} from 'rxjs/Observable';
import 'rxjs/add/operator/do';
import 'rxjs/add/operator/map';
import {Bankaccount} from '../model/bankaccount';

import {AppState} from '../model/app.state';
import {Store} from '@ngrx/store';
import * as BankaccountActions from './../store/actions/bankaccount.actions';

const BANKACCOUNTS_URL = 'http://localhost:8090/account/accounts/';

@Injectable()
export class BankaccountService {

  private headers = new HttpHeaders();

  bankaccounts$: Observable<Bankaccount[]>;

  constructor(private httpClient: HttpClient, private store: Store<AppState>) {
    this.headers = this.headers.set('Content-Type', 'application/json');
    this.headers = this.headers.set('Accept', 'application/json');
    this.bankaccounts$ = store.select('bankaccounts');
  }

  getBankaccounts() {
    this.httpClient.get<Bankaccount[]>(BANKACCOUNTS_URL).map((result: any) => {
      console.log('BankaccountService: fetched ' + result._embedded.accounts.length + ' bankaccounts from server');
      return result._embedded.accounts.sort((a, b) => a.id - b.id);
    }).subscribe((bankaccounts) => {
      console.log('BankaccountService: bankaccounts retrieved: ', bankaccounts);
      this.store.dispatch(new BankaccountActions.LoadBankaccounts(bankaccounts));
      console.log('BankaccountService: bankaccounts dispatched');
    });
  }
}

bankaccount.actions.ts

import {Action} from '@ngrx/store';
import {Bankaccount} from '../../model/bankaccount';

export enum BankaccountActionTypes {
  LOAD_BANKACCOUNT = '[Bankaccount] Load',
  ADD_BANKACCOUNT = '[Bankaccount] Add',
  UPDATE_BANKACCOUNT = '[Bankaccount] Update',
  REMOVE_BANKACCOUNT = '[Bankaccount] Remove'
}

export class LoadBankaccounts implements Action {
  readonly type = BankaccountActionTypes.LOAD_BANKACCOUNT;

  constructor(public payload: Bankaccount) {
  }
}

export class AddBankaccount implements Action {
  readonly type = BankaccountActionTypes.ADD_BANKACCOUNT;

  constructor(public payload: Bankaccount) {
  }
}

export class UpdateBankaccount implements Action {
  readonly type = BankaccountActionTypes.UPDATE_BANKACCOUNT;

  constructor(public payload: Bankaccount) {
  }
}

export class RemoveBankaccount implements Action {
  readonly type = BankaccountActionTypes.REMOVE_BANKACCOUNT;

  constructor(public payload: Bankaccount) {
  }
}

export type Actions = LoadBankaccounts | AddBankaccount | UpdateBankaccount | RemoveBankaccount;

bankaccount.reducer.ts

import {Bankaccount} from '../../model/bankaccount';
import * as BankaccountActions from './../actions/bankaccount.actions';

export function bankaccountReducer(state: Bankaccount[] = [], action: BankaccountActions.Actions) {
  switch (action.type) {
    case BankaccountActions.BankaccountActionTypes.LOAD_BANKACCOUNT:
      console.log('bankaccountReducer: loading data: %o', action.payload);
      return [...state, action.payload];
    case BankaccountActions.BankaccountActionTypes.ADD_BANKACCOUNT:
      console.log('bankaccountReducer: adding data %o', action.payload);
      return [...state, action.payload];
    case BankaccountActions.BankaccountActionTypes.UPDATE_BANKACCOUNT:
      console.log('bankaccountReducer: updating data for %o', action.payload);
      return state.map(bankaccount => {
        if (bankaccount.id !== action.payload.id) {
          return bankaccount;
        }
        return action.payload;
      });
    case BankaccountActions.BankaccountActionTypes.REMOVE_BANKACCOUNT:
      console.log('bankaccountReducer: removing bankaccount %o', action.payload);
      return state.filter(bankaccount => bankaccount.id !== action.payload.id);
    default:
      console.log('bankaccountReducer: default action', state);
      return state;
  }
}

app.state.ts

import {Bankaccount} from './bankaccount';

export interface AppState {
  readonly bankaccounts: Bankaccount[];
}

app.module.ts

// ... other imports
import {StoreModule} from '@ngrx/store';
import {bankaccountReducer} from './store/reducer/bankaccount.reducer';
import {BankaccountService} from './services/bankaccount.service';

@NgModule({
  declarations: [
    // ... declarations which have nothing to do with store ...
  ],
  imports: [
    // other imports
    StoreModule.forRoot({bankaccounts: bankaccountReducer})
  ],
  providers: [
    BankaccountService,
    {provide: APP_BASE_HREF, useValue: '/account'}
  ],
  bootstrap: [AppComponent]
})
export class AppModule {
}
...