- Вопрос или проблема
- Ответ или решение
- Ответ на вопрос: Angular .NET SPA – Реактивная форма не очищает значения при навигации
- Подход 1: Использование CanDeactivate для управления навигацией
- Подход 2: Удаление данных формы в ngOnDestroy
- Подход 3: Локальное хранилище для хранения состояния
- Подход 4: Перехват событий навигации
- Заключение
Вопрос или проблема
В настоящее время архитектура моего фронтенд-приложения выглядит примерно так:
<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 не очищаются в каждой ситуации, когда пользователь покидает вид.
В настоящее время они очищаются, если:
- страница обновлена
- данные были правильно отправлены (прошли валидацию), и пользователь затем нажимает кнопку “назад”
Данные не очищаются, если:
- пользователь взаимодействует с ссылкой в панели навигации. Панель навигации в настоящее время написана в корневом компоненте приложения.
- На локальном хосте, если я ввожу любой веб-сайт, а затем нажимаю кнопку “назад”
Самое худшее в том, что директивы 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();
}
});
}
Заключение
Попробуйте скомбинировать эти подходы для достижения наилучшего результата. Убедитесь, что все службы, маршруты и компоненты правильно настроены, чтобы избежать конфликтов. Удачи в решении вашей проблемы! Если у вас есть дополнительные вопросы, не стесняйтесь обращаться.