[этот вопрос основан на странице https://ngrx-forms.readthedocs.io/]

У меня есть множество тем (строк) внутри моего углового компонента. Я использую ngrx-store для управления состоянием вместе с ngrx-forms для управления формами. Во время инициализации компонента я отправляю некоторые действия для каждой темы внутри компонента.


 ngOnInit(): void {
    this.formState$ = this.store.pipe(select(s => s.filterByTopics.formState))
    this.topicsOptions$ = this.store.pipe(select(s => s.filterByTopics.topicsOptions))
    Object.keys(this.topics).forEach(topic => this.store.dispatch(new CreateTopicControlAction(topic)))
  }

Это отлично работает, и добавляются элементы управления ngrx-form.

Но настоящая проблема заключается в том, что если я снова посещаю тот же компонент снова, он повторно инициализирует действия (поскольку ngOnInit содержит все действия) и выдает ошибку:

Uncaught Error: Group 'filterByTopicsForm.topics' already has child control '0'!

image.png

Как я могу предотвратить это?

Есть ли другой обходной путь?

0
mx_code 22 Апр 2020 в 09:58

1 ответ

Лучший ответ

Автор ngrx-форм здесь.

Это не проблема ngrx-forms как таковая, а скорее общий вопрос о том, как предотвратить двойную инициализацию, когда состояние находится в хранилище и, следовательно, не связано со временем жизни компонента.

Я вижу здесь несколько вариантов:

  1. сбросить форму в ngOnDestroy, отправив SetValueAction с начальным значением, а также ResetAction (или создайте собственное действие для воссоздания состояния формы в редукторе); это имитирует поведение @ angular / forms, где форма живет только до тех пор, пока владеющий компонент; вот как это может выглядеть с настраиваемым действием с ngrx v8 +:

    const resetMyForm = createAction('MY_FORM/reset');
    
    const myFormReducer = createReducer(
      {
        formState: createFormGroupState('MY_FORM', INITIAL_FORM_VALUE),
      },
      onNgrxForms(),
      on(resetMyForm, ({ formState }, { lang, code }) => ({
        formState: createFormGroupState('MY_FORM', INITIAL_FORM_VALUE),
      })),
    );
    
  2. Проверить, инициализирована ли уже форма в компоненте

    ngOnInit(): void {
      this.formState$ = this.store.pipe(select(s => s.filterByTopics.formState))
      this.topicsOptions$ = this.store.pipe(select(s => s.filterByTopics.topicsOptions))
      Object.keys(this.topics).forEach(topic => {
        this.formState$.pipe(take(1)).subscribe(formState => {
          // how exactly this `if` looks like depends on your concrete form state shape
          if (!formState.controls.topics.controls[topic]) {
            this.store.dispatch(new CreateTopicControlAction(topic))
          }
        })
      })
    }
    
  3. Проверьте, инициализирована ли форма в редукторе

    const createTopicControl = createAction('MY_FORM/createTopicControl', (topic: string) => ({ topic }));
    
    const myFormReducer = createReducer(
      {
        formState: createFormGroupState('MY_FORM', INITIAL_FORM_VALUE),
      },
      onNgrxForms(),
      on(createTopicControl, (state, { topic }) => {
        if (state.formState.controls.topics.controls[topic]) {
          return state
        }
    
        // add form control ...
      }),
    );
    

Надеюсь, это поможет.

2
MrWolfZ 24 Апр 2020 в 16:57