Угловая 2/4 не позволяет пользователю покинуть компонент, если изменения не сохранены

У меня есть этот интерфейс, который я использую, чтобы не дать пользователю покинуть страницу

export interface ComponentCanDeactivate {
  canDeactivate: () => boolean;
}

@Injectable()
export class PendingChangesGuard implements CanDeactivate<ComponentCanDeactivate> {
  canDeactivate(component: ComponentCanDeactivate): boolean {
    return  component.canDeactivate() ?
     //code : //more code
  }
}

В одном из моих компонентов у меня есть следующий код

export class DashboardComponent implements ComponentCanDeactivate{
  @HostListener('window:beforeunload')
  canDeactivate(): boolean {
    return !this.isDirty;
  }

Моя проблема в том, что мой компонент -> (component: ComponentCanDeactivate) из PendingChangesGuard всегда нулевой, поэтому я получаю сообщение об ошибке

Невозможно вызвать canDeactivate() со значением NULL

У меня также есть эта настройка в моей маршрутизации

 path: 'dashboard',
        canDeactivate: [PendingChangesGuard],
        loadChildren: './views/dashboard/dashboard.module#DashboardModule'

Может кто-нибудь сказать мне, что я делаю не так?

3 ответа

Решение

Проблема была вызвана отложенной загрузкой

Вместо того, чтобы иметь это в вашем маршрутизации приложения:

path: 'dashboard',
        canDeactivate: [PendingChangesGuard], <-- causing issue
        loadChildren: './views/dashboard/dashboard.module#DashboardModule'

Вам нужно удалить canDeactive из маршрутизации приложения и переместить его в маршрутизацию модуля.

const routes: Routes = [
  {
    path: '',
    component: DashboardComponent,
    canDeactivate: [ PendingChangesGuard ]
  }

Я реализую так

Выключена-сторожевой service.ts

export interface CanComponentDeactivate {
  canDeactivate: () => Observable<boolean> | Promise<boolean> | boolean;
}

@Injectable()
export class DeactivateGuardService implements  CanDeactivate<CanComponentDeactivate>{

  canDeactivate(component: CanComponentDeactivate) {
    return component.canDeactivate ? component.canDeactivate() : true;
  }
}

Component.ts

checkSave(): Promise<boolean> {
    var prom = new Promise<boolean>((resolve, reject) => {
      //check saved change
        if(saved) resolve(true);
        else reject(false);
    });
    return prom;
  }

  canDeactivate(): Promise<boolean> {

    return this.checkSave().catch(function () {
      return false;
    });
  }

В вашем PendingChangesGuard попробуйте ввести сам компонент, а не интерфейс:

export class PendingChangesGuard implements CanDeactivate<DashboardComponent> {
  constructor() {}
  canDeactivate(component: DashboardComponent): boolean {
  ...
  }

Вы не можете внедрить интерфейс, используя Angular DI, так как интерфейсы являются просто конструкциями Typescript и не существуют в коде Javascript, созданном в процессе компиляции.

Для получения дополнительной информации, посмотрите на этот вопрос SO.

Другие вопросы по тегам