问题描述
我正在尝试在组件中添加 CanDeactivate
功能.一个输入
字段和按钮的表单.我想如果用户在输入字段中输入某些内容并不提交而移至下一个屏幕
,它将显示一个对话框.如果用户从对话框中输入 yes
,则转到下一个组件,否则它将保留在同一屏幕中.
I am trying to add CanDeactivate
functionality in my component.I have aform in which there is one input
field and button. i want if user enter something in input field and move to next screen
without submit it will show a dialog box .if user enter yes
from the dialog bix then it go to next component else it remain in same screen .
这是我的代码 https://stackblitz.com/edit/angular-ctwnid?file = src%2Fapp%2Fhello.component.ts
import {CanDeactivate} from '@angular/router';
import { HelloComponent } from './hello.component';
export default class DeactivateGuard implements CanDeactivate<HelloComponent> {
canDeactivate(component: HelloComponent): boolean {
if (!component.canDeactivate()) {
if (confirm('You have unsaved changes! If you leave, your changes will be lost.')) {
return true;
} else {
return false;
}
}
return true;
}
}
当前,当我在 input
字段上键入内容并单击 next
按钮时,它给我错误
currently when I am typing something on input
field and click next
button it give me error
ERROR
Error: Uncaught (in promise): TypeError: Cannot read property 'ngInjectableDef' of undefined
TypeError: Cannot read property 'ngInjectableDef' of undefined
at resolveNgModuleDep (https://angular-ctwnid.stackblitz.io/turbo_modules/@angular/[email protected]/bundles/core.umd.js:9309:31)
at NgModuleRef_.get (https://angular-ctwnid.stackblitz.io/turbo_modules/@angular/[email protected]/bundles/core.umd.js:10003:16)
at PreActivation.getToken (https://angular-ctwnid.stackblitz.io/turbo_modules/@angular/[email protected]/bundles/router.umd.js:3014:25)
at MergeMapSubscriber.eval [as project] (https://angular-ctwnid.stackblit
推荐答案
我认为理想的实现方法是创建一个接口,以使Guard可以重用.
I think an ideal implementation would be to create an interface that would allow the Guard to be reusable.
方法如下:
import { Injectable } from '@angular/core';
import { CanDeactivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
export interface CanComponentDeactivate {
confirm(): boolean;
}
@Injectable()
export class DeactivateGuard implements CanDeactivate < CanComponentDeactivate > {
canDeactivate(
component: CanComponentDeactivate,
next: ActivatedRouteSnapshot,
state: RouterStateSnapshot
): boolean {
if (!component.confirm()) {
return confirm('You have unsaved changes! If you leave, your changes will be lost.');
}
}
}
然后,应在此 CanComponentDeactivate
接口上实现必须放置此防护罩的组件.这就是强制执行 confirm
方法的方法,从该方法中,返回的布尔值就是您要在后卫的 canDeactivate
方法中检查的值.
Then this CanComponentDeactivate
Interface should be implemented the component on which you have to place this guard. That's how it would be forced to implement the confirm
method from where the returned boolean value is what you'd want to check in the canDeactivate
method of your guard.
与此类似的东西:
import { Component, Input } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { CanComponentDeactivate } from './deactivate.guard';
@Component({
selector: 'hello',
template: `<h1>Hello {{name}}!</h1>
<form novalidate [formGroup]="sfrm" class="calform">
<input type="text" formControlName="name"/>
<button type="submit">submit</button>
</form>
<a [routerLink]="['/next']">next</a>
`,
styles: [`h1 { font-family: Lato; }`]
})
export class HelloComponent implements CanComponentDeactivate {
@Input() name: string;
sfrm: FormGroup
constructor(private fb: FormBuilder) {
this.sfrm = this.fb.group({
name: ['']
});
}
confirm() {
return this.sfrm.submitted || !this.sfrm.dirty;
}
}
最后一件事情是将Guard作为提供者添加.毕竟,这是一项服务.因此,将其添加到 providers
数组:
One final thing would be to also add the Guard as a provider. After all, it's a service. So add it to the providers
array:
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';
import { HttpClientModule } from '@angular/common/http';
import { RouterModule, Routes } from '@angular/router';
import { ReactiveFormsModule } from '@angular/forms';
import { AppComponent } from './app.component';
import { HelloComponent } from './hello.component';
import { ErrorComponent } from './error.component';
import { DeactivateGuard } from './deactivate.gaurd';
import { TestService } from './test.service';
import { TestResolver } from './test.resolver';
import { HTTP_INTERCEPTORS } from '@angular/common/http';
import { NextComponent } from './next/next.component';
const routes: Routes = [{
path: 'home',
component: HelloComponent,
canDeactivate: [DeactivateGuard]
},
{
path: 'next',
component: NextComponent
},
{
path: '',
redirectTo: '/home',
pathMatch: 'full'
}
];
@NgModule({
imports: [
BrowserModule,
ReactiveFormsModule,
RouterModule.forRoot(routes),
HttpClientModule,
FormsModule
],
declarations: [
AppComponent,
HelloComponent,
ErrorComponent,
NextComponent
],
bootstrap: [AppComponent],
providers: [
TestService,
TestResolver,
DeactivateGuard
]
})
export class AppModule {}
这应该使警卫为您工作.这是您的 更新后的StackBlitz
This should make the guard work for you. Here's your Updated StackBlitz
这篇关于如何在组件中添加CanDeactivate功能?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!