Обновление списка сущностей в таблице ngrx новыми отфильтрованными данными - PullRequest
0 голосов
/ 24 декабря 2018

У меня есть угловое приложение, которое я использую с помощью ngrx и эффектов.На одном маршруте у меня есть список предупреждений, которые я получаю из REST API.Это делается путем вызова конечной точки / alerts, вызываемой в ngOnit через эффект.Однако теперь я хочу, чтобы над списком предупреждений в таблице было несколько фильтров: фильтр по статусу, фильтр по уполномоченному, созданный до, созданный после и т. Д. Итак, в принципе, каков наилучший подход для добавления фильтров в таблицы и обновления существующего набора объектов?с отфильтрованными?Мой первоначальный подход, подробно описанный ниже, возвращает отфильтрованные оповещения, но список оповещений всегда отображает исходный полный набор оповещений, а не отфильтрованные.

Так что при выбранном изменении ...

select.filter.html:

<div class="m-b-2">
<label>Status:</label>
<div class="ncc-select ncc-select-inline">
    <select id="nccSelect" class="form-control" #status (change)="statusType(status.value)">
        <option value="">All</option>
        <option value="open">Open</option>
        <option value="ticketed">Ticketed</option>
        <option value="closed">Closed</option>
    </select>
</div>

Затем я запускаю действие:

select.filter.ts:

...

statusType(value) {
    this.store.dispatch(new fromAlerts.FetchAlertsByStatus(value));
}

...

, который выбирается в эффекте и возвращает новый набор данных следующим образом.

effect.ts

    ...

@Effect()
loadAlertsByStatus$ = this.actions$.ofType(alertFiltersActions.FETCH_ALERTS_BY_STATUS)
    .pipe(
        switchMap((action) => {
            return this.alertsService.getAlertsByStatus(action).pipe(
                map(alerts => new alertsActions.LoadAlertsSuccess(alerts)),
                catchError(error => of(new alertsActions.LoadAlertsFail(error)))
            );
        })
    );

...

ОднакоМой alerts.reducer.ts продолжает возвращать тот же исходный набор сущностей, а не новый «отфильтрованный» набор оповещений

alerts.reducer.ts:

import * as fromAlerts from '../actions/alerts.actions';
import * as fromAlertFilters from '../actions/filters.actions';
import { Alert } from '../../models/alert.model';

export interface AlertState {
    entities: {[id: number]: Alert};
    loaded: boolean;
    loading: boolean;
    alertSelected: Alert;
    inspectorOpen: boolean;
}

export const initialState: AlertState = {
    entities: {},
    loaded: false,
    loading: false,
    alertSelected: null,
    inspectorOpen: false
};

export function reducer(state = initialState, action: any): AlertState {
    switch (action.type) {
        case fromAlerts.LOAD_ALERTS: {
            return {
                ...state,
                loading: true
            };
        }
        case fromAlerts.LOAD_ALERTS_SUCCESS: {

            const alerts = action.payload;
            const entities = alerts.reduce(
                (entities: {[id: number]: Alert}, alert: Alert) => {
                    return {
                        ...entities,
                        [alert._id]: alert
                    };
            }, {
                ...state.entities
            }
            );

            return {
                ...state,
                loading: false,
                loaded: true,
                entities
            };
        }
        case fromAlerts.LOAD_ALERTS_FAIL: {
            return {
                ...state,
                loading: false,
                loaded: false
            };
        }
        case fromAlerts.SELECT_ALERT: {
            const alert = action.payload;
            return {
                ...state,
                alertSelected: alert,
                inspectorOpen: true
            };
        }
        case fromAlerts.CLOSE_INSPECTOR: {
            return {
                ...state,
                inspectorOpen: false
            };
        }
        case fromAlertFilters.FETCH_ALERTS_BY_STATUS: {
            return {
                ...state,
                loading: true
            };
        }
    }

    return state;
}

// export different levels of state
export const getAlertsEntities = (state: AlertState) => state.entities;
export const getAlertsLoading = (state: AlertState) => state.loading;
export const getAlertsLoaded = (state: AlertState) => state.loaded;
export const getSelectedAlert = (state: AlertState) => state.alertSelected;
export const getInspectorState = (state: AlertState) => state.inspectorOpen;

alerts-list.component.ts:

import { Component, OnInit } from '@angular/core';

import { Store, select } from '@ngrx/store';
import { Observable } from 'rxjs/Observable';
import * as fromStore from '../store';

import { Alert } from '../models/alert.model';

import { AlertsService } from './../services/alerts.service';
import { ActivatedRoute } from '@angular/router';
import { getAlertsLoading } from '../store/reducers/alerts.reducer';
declare var require: any;
const _ = require('underscore');

@Component({
  selector: 'app-list-alerts',
  templateUrl: './list-alerts.component.html',
  styleUrls: ['./list-alerts.component.css']
})
export class ListAlertsComponent implements OnInit {

    alerts$: Observable<Alert[]>;
    realAlerts: any;
    quickViewOpen$: Observable<boolean>;
    alert: any;
    loading: Observable<boolean>;

    constructor(
        private _alertsService: AlertsService,
        private route: ActivatedRoute,
        private store: Store<fromStore.AlertsState>
        ) { }

    ngOnInit() {
        this.loading = this.store.select(fromStore.getAlertsLoading);
        this.alerts$ = this.store.pipe(
            select(fromStore.getAllAlerts)
        );
        this.store.dispatch(new fromStore.LoadAlerts());
        this.quickViewOpen$ = this.store.select(fromStore.getInspectorStatus);
    }

}

alerts.selectors.ts

import { createSelector } from '@ngrx/store';

import * as fromRoot from '../../../../../store';
import * as fromFeature from '../reducers';
import * as fromAlerts from '../reducers/alerts.reducer';

import { Alert } from '../../models/alert.model';

export const getAlertState = createSelector(
    fromFeature.getAlertsState,
    (state: fromFeature.AlertsState) => state.alerts
);

export const getAlertsEntities = createSelector(
    getAlertState,
    fromAlerts.getAlertsEntities
);


export const getAllAlerts = createSelector(getAlertsEntities, entities => {
    return Object.keys(entities).map(id => entities[id]);
});

export const getSelectedAlert = createSelector(
    getAlertsEntities,
    fromRoot.getRouterState,
    (entities, router): Alert => {
        return router.state && entities[router.state.params.id];
    }
);

export const getAlertsLoading = createSelector(getAlertState, fromAlerts.getAlertsLoading);
export const getAlertsLoaded = createSelector(getAlertState, fromAlerts.getAlertsLoaded);
export const getCurrentlySelectedAlert = createSelector(getAlertState, fromAlerts.getSelectedAlert);
export const getInspectorStatus = createSelector(getAlertState, fromAlerts.getInspectorState);

Также этот подход будет работать длямногократная фильтрация или есть лучший подход?Я действительно не хочу использовать Angular Material, если смогу избежать этого.

...