Angular 4 store observable заполнен слишком рано?

У меня есть это приложение, в котором есть магазин и компонент страницы.

Наличие этого компонента страницы:

import {AfterViewInit, Component, OnDestroy, OnInit} from '@angular/core';
import {ActivatedRoute, Params} from '@angular/router';
import {Store} from '@ngrx/store';
import {Translation, TranslationService} from 'angular-l10n';
import * as _ from 'lodash';
import * as moment from 'moment';
import {Observable} from 'rxjs/Observable';
import {of} from 'rxjs/observable/of';
import {Language, LoadLanguagesAction} from '../../../shared';
import {DateTimeFormatService} from '../../../shared';
import {TagsList} from '../../../shared/models/tags-list';
import * as fromRoot from '../../../shared/reducers';
import {LoadSubscriptionDetailAction, LoadSubscriptionDetailSuccessAction} from '../../actions/subscription';
import {EditSubscriptionForm} from '../../models/edit-subscription-form';
import {Subscriptions} from '../../models/subscriptions';
import * as fromSubscription from '../../reducers';
import {Subscription} from 'rxjs/Subscription';

@Component(
  { selector: 'storever-subscription-detail', templateUrl: './subscription-detail.component.html', styleUrls: ['./subscription-detail.component.scss'] })
export class SubscriptionDetailComponent extends Translation implements OnInit, OnDestroy {
  subscription$: Observable<Subscriptions>;
  languages$: Observable<Language[]>;
  tagsList$: Observable<TagsList[]>;
  first: Subscriptions;
  private actionsSubscription: Subscription;
  name: string;
  created: string;
  update: string;
  createdP: string;
  updateP: string;
  createdS: string;
  updateS: string;

  constructor(private store: Store<fromSubscription.AppState>, private activatedRoute: ActivatedRoute, translation: TranslationService) {
    super(translation);
    this.actionsSubscription = activatedRoute.params.pluck<Params, string>('subscriptionId')
      .distinctUntilChanged()
      .switchMap(subscriptionId => of(new LoadSubscriptionDetailAction(subscriptionId)))
      .subscribe(store);
    this.subscription$ = this.store.select(fromSubscription.selectors.getSubscription);
    this.languages$ = this.store.select(fromRoot.selectors.getLanguages);
    this.tagsList$ = this.store.select(fromRoot.selectors.getTags);
    this.subscription$.subscribe(data => (data ? console.log('dataaaaaaaaaa', data) : null ), err => console.log('err', err));
    /*
    this.created = moment(this.subscription$.created).format('DD/MM/YYYY h:mm:ss');
    this.update = moment(this.subscription$.updated).format('DD/MM/YYYY h:mm:ss');
    this.createdP = moment(this.subscription$.player.created).format('DD/MM/YYYY h:mm:ss');
    this.updateP = moment(this.subscription$.player.updated).format('DD/MM/YYYY h:mm:ss');
    this.createdS = moment(this.subscription$.site.created).format('DD/MM/YYYY h:mm:ss');
    this.updateS = moment(this.subscription$.site.updated).format('DD/MM/YYYY h:mm:ss');
    */
  }
  get dateTimeWithSecondsAndTimezoneFormat(): string { return DateTimeFormatService.display.dateTimeWithSecondsAndTimezone; }

  ngOnInit() {
    this.store.dispatch(new LoadLanguagesAction());

  }



  ngOnDestroy() {
    super.cancelParamSubscriptions();
    this.actionsSubscription.unsubscribe();
  }

  saveMedia(subscriptions: EditSubscriptionForm): void {}
}

В качестве сервиса у меня есть:

import {Injectable} from '@angular/core';
import {Http} from '@angular/http';
import {Observable} from 'rxjs/Observable';

import {AppSettingsService, BaseRestService, BlockUIService, SendBackResult} from '../../shared';
import {Subscriptions} from '../models/subscriptions';

@Injectable()
export class SubscriptionService extends BaseRestService {
  constructor(http: Http, appSettingsService: AppSettingsService, blockUIService: BlockUIService) { super(http, appSettingsService, blockUIService); }

  protected get className(): string { return 'MediaService'; }

  protected get isAnonymous(): boolean { return false; }

  load(clientId: string, subscriptionId: string): Observable<SendBackResult<Subscriptions>> {
    return this.get<Subscriptions>(`/clients/${clientId}/audio/subscriptions/${subscriptionId}`);
  }

  /*
  update(clientId: string, mediaId: number, media: Media): Observable<SendBackResult<Media>> {
    return this.put<Media>(`/clients/${clientId}/audio/media/commercials/${mediaId}`, media);
  }
  */
}

Редуктор:

import {Action} from '@ngrx/store';
import * as _ from 'lodash';

import {UserContextActionTypes} from '../../shared';
import {
  LoadSubscriptionDetailAction,
  LoadSubscriptionDetailFailAction,
  LoadSubscriptionDetailSuccessAction,
  SubscriptionDetailActionTypes
} from '../actions/subscription';
import {Subscriptions} from '../models/subscriptions';

export interface SubscriptionsDetailState {
  value: Subscriptions;
  submitting: boolean;
}

const initialState: SubscriptionsDetailState = {
  value: undefined,
  submitting: false
};

export function SubscriptionDetailReducer(state = initialState, action: Action): SubscriptionsDetailState {
  switch (action.type) {
    case SubscriptionDetailActionTypes.LOAD_SUCCESS:
      return handleLoadSuccessAction(state, action);
    case SubscriptionDetailActionTypes.LOAD_FAIL:
      return handleLoadErrorActions(state);
    case UserContextActionTypes.CHANGE_CLIENT:
      return handleChangeClientAction();
    default:
      return state;
  }
}

function handleLoadSuccessAction(state: SubscriptionsDetailState, action: LoadSubscriptionDetailSuccessAction): SubscriptionsDetailState {
  const newState = _.clone(state);
  newState.value = action.payload;
  return newState;
}

function handleLoadErrorActions(state: SubscriptionsDetailState): SubscriptionsDetailState {
  const newState = _.clone(state);
  newState.value = undefined;
  return newState;
}

function handleChangeClientAction(): SubscriptionsDetailState {
  return { value: undefined, submitting: false };
}

export const SubscriptionDetailSelectors = {
  value: (state: SubscriptionsDetailState) => _.get<Subscriptions>(state, 'value'),
  submitting: (state: SubscriptionsDetailState) => _.get<boolean>(state, 'submitting', false)
};

Редуктор index.ts:

import {ActionReducerMap, createFeatureSelector, createSelector, MemoizedSelector} from '@ngrx/store';
import * as _ from 'lodash';
import * as fromRoot from '../../shared/reducers';
import {SubscriptionFilter} from '../models/subscription-filter';
import {Subscriptions} from '../models/subscriptions';

import {SubscriptionsListReducer, SubscriptionsListSelectors, SubscriptionsListState} from './subscriptions';
import {SubscriptionDetailReducer, SubscriptionDetailSelectors, SubscriptionsDetailState} from './subscription';

export interface SubscriptionsState { subscriptions: SubscriptionsListState; subscription: SubscriptionsDetailState;}

export interface AppState extends fromRoot.AppState { subscriptions: SubscriptionsState; subscription: SubscriptionsDetailState; }

export const reducers: ActionReducerMap<SubscriptionsState> = {
  subscriptions: SubscriptionsListReducer,
  subscription: SubscriptionDetailReducer
};

const getCampaignsState = createFeatureSelector('campaigns');
const rootSelectors = {
  subscriptions: createSelector(getCampaignsState, (state: SubscriptionsState) => _.get<SubscriptionsListState>(state, 'subscriptions')),
  subscription: createSelector(getCampaignsState, (state: SubscriptionsState) => _.get<SubscriptionsDetailState>(state, 'subscriptions'))
};

export interface Selectors {
  getShowFilter: MemoizedSelector<AppState, boolean>;
  getQuickSearch: MemoizedSelector<AppState, string>;
  getFilter: MemoizedSelector<AppState, SubscriptionFilter>;
  getPage: MemoizedSelector<AppState, number>;
  getPageSize: MemoizedSelector<AppState, number>;
  getOrderBy: MemoizedSelector<AppState, string>;
  getCount: MemoizedSelector<AppState, number>;
  getSubscriptions: MemoizedSelector<AppState, Subscriptions[]>;
  getSubscription: MemoizedSelector<AppState, Subscriptions>;
}

export const selectors: Selectors = {
  getShowFilter: createSelector(rootSelectors.subscriptions, SubscriptionsListSelectors.showFilter),
  getQuickSearch: createSelector(rootSelectors.subscriptions, SubscriptionsListSelectors.quickSearch),
  getFilter: createSelector(rootSelectors.subscriptions, SubscriptionsListSelectors.filter),
  getPage: createSelector(rootSelectors.subscriptions, SubscriptionsListSelectors.page),
  getPageSize: createSelector(rootSelectors.subscriptions, SubscriptionsListSelectors.pageSize),
  getOrderBy: createSelector(rootSelectors.subscriptions, SubscriptionsListSelectors.orderBy),
  getCount: createSelector(rootSelectors.subscriptions, SubscriptionsListSelectors.count),
  getSubscriptions: createSelector(rootSelectors.subscriptions, SubscriptionsListSelectors.array),
  getSubscription: createSelector(rootSelectors.subscription, SubscriptionDetailSelectors.value),
};

Действие:

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

import {type} from '../../shared';
import {Subscriptions} from '..//models/subscriptions';

export const SubscriptionDetailActionTypes = {
  LOAD: type('[ Subscription] Load'),
  LOAD_SUCCESS: type('[ Subscription] Load Success'),
  LOAD_FAIL: type('[ Subscription] Load Fail')
};

export class LoadSubscriptionDetailAction implements Action {
  readonly type = SubscriptionDetailActionTypes.LOAD;
  constructor(public payload?: string) {}
}

export class LoadSubscriptionDetailSuccessAction implements Action {
  readonly type = SubscriptionDetailActionTypes.LOAD_SUCCESS;
  constructor(public payload?: Subscriptions) {}
}

export class LoadSubscriptionDetailFailAction implements Action {
  readonly type = SubscriptionDetailActionTypes.LOAD_FAIL;
  constructor(public payload?: number) {}
}

Эффект:

import {Injectable} from '@angular/core';
import {Response} from '@angular/http';
import {Router} from '@angular/router';
import {Actions, Effect} from '@ngrx/effects';
import {Action, Store} from '@ngrx/store';
import {TranslationService} from 'angular-l10n';
import * as _ from 'lodash';

import {ArrayResponse, BaseEffect, error, SendBackResult} from '../../shared';
import * as fromRoot from '../../shared/reducers';
import {Subscriptions} from '..//models/subscriptions';
import {SubscriptionDetailActionTypes,
  LoadSubscriptionDetailFailAction,
  LoadSubscriptionDetailSuccessAction,
  LoadSubscriptionDetailAction} from '../actions/subscription';
import * as fromSubscriptions from '../reducers/';
import {SubscriptionService} from '../services/subscription.service';

@Injectable()
export class SubscriptionEffect extends BaseEffect {
  private client$ = this.store.select(fromRoot.selectors.getCurrentClient).filter(client => !_.isEmpty(client));


  @Effect()
  load$ = this.actions$.ofType(SubscriptionDetailActionTypes.LOAD)
    .delayWhen(() => this.client$)
    .debug('Load Subscription details action received.')
    .map((action: LoadSubscriptionDetailAction) => action.payload)
    .withLatestFrom(this.client$)
    .switchMap(([payload, client]) => this.subscriptionService.load(client.uuid, payload)
      .map((result: SendBackResult<Subscriptions>) => new LoadSubscriptionDetailSuccessAction(result.data))
      .catch((res: Response) => this.catchResponseError(res)));

  @Effect()
  loadFail$ = this.actions$.ofType(SubscriptionDetailActionTypes.LOAD_FAIL)
    .debug('A server error occurred while retrieving media details.')
    .map(() => error(this.translation.translate('SUBSCRIPTION_LOAD_ERROR'), this.translation.translate('TOAST_ERROR_TITLE')));

  constructor(private actions$: Actions,
              private store: Store<fromSubscriptions.AppState>,
              private translation: TranslationService,
              private subscriptionService: SubscriptionService,
              router: Router) {
    super(router);
  }

  protected handleUnhandledError(response: Response): Action { return new LoadSubscriptionDetailFailAction(response.status); }
}

Все идет нормально. Но чень я вызываю подписку в компоненте страницы не получаю console.log, еще хуже подписка не грузится, а значит не знает имя так как не печатается. Я полностью потерян. Вызов происходит, все в порядке, когда я отлаживаю полезную нагрузку, она всегда есть, подписки на this.subscription$ нет.

Он пытается добавить это в ближайшее время, я думаю, потому что он пытается это сделать до звонка?

Добавлен образ консоли.

консоль приложения


person user3806549    schedule 02.10.2017    source источник


Ответы (1)


Index.ts не был установлен правильно,

При наличии одинаковых ошибок проверьте, сохранены ли они в магазине. Если сохранено, проверьте селекторы, потому что, если оно есть в магазине, вам просто нужно его достать.

const rootSelectors = {
  subscriptions: createSelector(getCampaignsState, (state: SubscriptionsState) => _.get<SubscriptionsListState>(state, 'subscriptions')),
  subscription: createSelector(getCampaignsState, (state: SubscriptionsState) => _.get<SubscriptionsDetailState>(state, 'subscription'))
};
person user3806549    schedule 03.10.2017