【问题标题】:how to add CanDeactivate functionality in component?如何在组件中添加 CanDeactivate 功能?
【发布时间】:2018-08-27 17:30:43
【问题描述】:

我正在尝试在我的组件中添加CanDeactivate 功能。我有一个 包含one input 字段和按钮的表单。我想如果用户在输入字段中输入内容并移动到下一个 screen 而不提交它将显示一个对话框。如果用户从对话框 bix 输入 yes 然后它转到下一个组件,否则它会保持在同一个屏幕中。

这是我的代码 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 按钮时,它给了我错误

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/core@6.0.0/bundles/core.umd.js:9309:31)
at NgModuleRef_.get (https://angular-ctwnid.stackblitz.io/turbo_modules/@angular/core@6.0.0/bundles/core.umd.js:10003:16)
at PreActivation.getToken (https://angular-ctwnid.stackblitz.io/turbo_modules/@angular/router@6.0.0/bundles/router.umd.js:3014:25)
at MergeMapSubscriber.eval [as project] (https://angular-ctwnid.stackblit

【问题讨论】:

    标签: javascript angular


    【解决方案1】:

    我认为理想的实现是创建一个允许 Guard 可重用的接口。

    方法如下:

    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 方法中检查的值。

    类似这样的事情:

    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 数组中:

    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 {}
    

    这应该让守卫为你工作。这是你的Updated StackBlitz

    【讨论】:

      【解决方案2】:

      你还没有通过 app.module.ts 提供者的 deactivae 保护,编辑你的 stackbiltz

           providers: [TestService,TestResolver,DeactivateGuard  
        ]
      

      【讨论】:

        猜你喜欢
        • 2021-08-12
        • 2011-08-27
        • 2017-11-19
        • 2018-05-05
        • 1970-01-01
        • 1970-01-01
        • 2021-04-06
        • 1970-01-01
        • 2020-11-18
        相关资源
        最近更新 更多