使用一个自己的小商店实现(有效),我试图将ngrx / store引入有角度的6应用程序中。版本是:
"@ngrx/core": "^1.2.0",
"@ngrx/store": "^6.1.0"
该应用程序是一个有角度的前端,可通过Spring应用程序通过http获取/写入数据到数据库。首次加载BankaccountListComponent时,它将通过BankaccountService从数据库中提取银行帐户列表,并随后从spring应用程序中提取。 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 {
}