Angular .NET SPA – Реактивная форма не очищает значения, когда пользователь покидает страницу

Вопрос или проблема

В настоящее время архитектура моего фронтенд-приложения выглядит примерно так:

<app root> <router-outlet></router-outlet> </app root>

Router-outlet по умолчанию начинает с пути, указывающего на дочерний компонент под названием IdRequestFormComponent:

export class NetIdRequestFormComponent implements OnInit, OnDestroy {

  constructor(private fb: FormBuilder, private http: HttpClient, private router: Router) {

    //this.router.routeReuseStrategy.shouldReuseRoute = () => {
    //  return false;
    //};
   
    this.netIdRequestForm = this.fb.group({
        // управление инициализировано
    });

    ngOnDestroy(): void {
      this.netIdRequestForm.reset();
    }
<form [formGroup]="netIdRequestForm" (ngSubmit)="onSubmit()">
  <div class="mb-3 border border-light">
    <div class="panel-heading mb-3">Общая информация</div>
    <div class="mb-3 px-3">
      <label class="form-label fw-bold">Запрос доступа для:</label>
      <div class="d-flex">
        <div class="form-check px-4">
          <input type="radio" class="form-check-input" name="accessFor" formControlName="accessFor" value="Myself" /> 
          <label class="form-check-label" for="accessFor">
            Себя
          </label>
        </div>
        <div class="form-check px-4">
          <input type="radio" class="form-check-input" name="accessFor" formControlName="accessFor" value="Someone else" />
          <label class="form-check-label" for="accessFor">
            Другого человека
          </label>
        </div>
      </div>

      <p *ngIf="this.pressedSubmit && netIdRequestForm.get('accessFor')?.errors" class="mb-3 text-danger"> Пожалуйста, выберите один вариант. </p>
    </div>
  </div>
<!--Дополнительные поля... -->
</form>

Router outlet по умолчанию отображает дочерний компонент под названием IdRequestFormComponent. Этот компонент содержит html/ts код для отображения реактивной формы (группы форм, конструктора форм и т.д.). Я инициализирую эту форму с помощью конструктора класса. В целом, это работает хорошо.

Моя текущая проблема: данные формы в IdRequestFormComponent не очищаются в каждой ситуации, когда пользователь покидает вид.

В настоящее время они очищаются, если:

  1. страница обновлена
  2. данные были правильно отправлены (прошли валидацию), и пользователь затем нажимает кнопку “назад”

Данные не очищаются, если:

  1. пользователь взаимодействует с ссылкой в панели навигации. Панель навигации в настоящее время написана в корневом компоненте приложения.
  2. На локальном хосте, если я ввожу любой веб-сайт, а затем нажимаю кнопку “назад”

Самое худшее в том, что директивы NgIf в HTML IdRequestFormComponent не распознаются, если пользователь вводит данные для активации, покидает страницу с помощью ссылки, а затем использует кнопку “назад” браузера. Данные все еще там, но ngIf оценивается как ложное.

Буду признателен за любые идеи, и я могу предоставить больше кода/описаний архитектуры по мере необходимости. Спасибо.

Пробовал использовать ngOnDestroy для вызова form.reset, но, похоже, точка останова в этой функции не срабатывает.

Также пробовал использовать canDeactivate с кастомным классом в классе маршрутизации, но, похоже, изменения в поведении не произошло. Также возможно, что я реализовал это неправильно:

const routes: Routes = [
  { path: '', component: NetIdRequestFormComponent, canDeactivate: [DeactivationGuard]},
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }

___________________________________

@Injectable()
export class DeactivationGuard implements CanDeactivate<any> {
  canDeactivate(component: any, currentRoute: ActivatedRouteSnapshot, currentState: RouterStateSnapshot, nextState: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
    const confirmation = confirm('Вы уверены, что хотите покинуть страницу с несохраненными данными?'); // это подтверждение браузера никогда не вызывается!!!
    console.log("мы деактивируем");
      if (confirmation) return true;
      else return false;
    }

}

Как видно из комментария внутри кода, API подтверждения браузера не вызывается при переходе на другую страницу, как ожидалось. Я убедился, что добавил DeactivationGuard в провайдеры в app.module.ts.

Ответ или решение

Ответ на вопрос: Angular .NET SPA – Реактивная форма не очищает значения при навигации

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

Подход 1: Использование CanDeactivate для управления навигацией

Как вы уже пробовали использовать CanDeactivate, этот подход весьма эффективен для контроля навигации, особенно если необходимо подтвердить намерение пользователя покинуть страницу с несохраненными данными. Тем не менее, вы упомянули, что функция подтверждения не вызывается при навигации. Убедитесь, что ваш маршрут правильно настроен с использованием canDeactivate.

Пример правильной настройки маршрута:

const routes: Routes = [
  { path: '', component: NetIdRequestFormComponent, canDeactivate: [DeactivationGuard] },
];

И корректная реализация DeactivationGuard:

@Injectable({
  providedIn: 'root'
})
export class DeactivationGuard implements CanDeactivate<NetIdRequestFormComponent> {
  canDeactivate(
    component: NetIdRequestFormComponent,
  ): Observable<boolean> | Promise<boolean> | boolean {
    const confirmation = confirm('Вы уверены, что хотите покинуть страницу с несохраненными данными?');
    return confirmation;
  }
}

Подход 2: Удаление данных формы в ngOnDestroy

Вы указали, что попытка использовать ngOnDestroy для очистки формы не сработала. Убедитесь, что ngOnDestroy правильно реализован внутри вашего компонента:

export class NetIdRequestFormComponent implements OnInit, OnDestroy {
  netIdRequestForm: FormGroup;

  constructor(private fb: FormBuilder, private router: Router) {
    this.netIdRequestForm = this.fb.group({
      accessFor: [''], // инициализация других полей
    });
  }

  ngOnInit(): void {
    // Здесь можно добавить логику при инициализации
  }

  ngOnDestroy(): void {
    this.netIdRequestForm.reset();
  }

  onSubmit(): void {
    if (this.netIdRequestForm.valid) {
      // логика отправки формы
      this.router.navigate(['/next-route']); // навигация после успешной отправки
    }
  }
}

Подход 3: Локальное хранилище для хранения состояния

Вы можете использовать локальное хранилище (LocalStorage) для сохранения состояния формы. Это способ сохранить данные между переходами страницы и проблемы, связанные с очисткой формы, могут быть решены следующим образом:

ngOnInit(): void {
  const savedFormData = localStorage.getItem('netIdRequestForm');
  if (savedFormData) {
    this.netIdRequestForm.setValue(JSON.parse(savedFormData));
  }

  this.netIdRequestForm.valueChanges.subscribe(value => {
    localStorage.setItem('netIdRequestForm', JSON.stringify(value));
  });
}

ngOnDestroy(): void {
  localStorage.removeItem('netIdRequestForm');
}

Подход 4: Перехват событий навигации

Если вам не удастся решить проблему с помощью вышеуказанных методов, попробуйте перехватить события навигации в вашем Router:

constructor(private router: Router) {
  this.router.events.subscribe(event => {
    if (event instanceof NavigationStart) {
      // Очистка данных перед навигацией
      this.netIdRequestForm.reset();
    }
  });
}

Заключение

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

Оцените материал
Добавить комментарий

Капча загружается...