路线更改前的Angular 5添加事件

Js *_*Lim 7 intercept typescript angular

我想在用户单击<a href="...">链接之前添加一个警报对话框。

<a>链接有2种类型

  1. 在Angular范围内重定向 <a routerLink="/path/to/dest">
  2. 在Angular应用之外重定向 <a href="http://www.somewhere.com" target="_blank">

我希望当用户尝试超出Angular范围时能够显示一个警告框

警报对话框

我想应用于所有<a>点击事件(有点像预钩)

有什么办法可以做到这一点?

Con*_*Fan 5

要链接到Angular应用程序的其他视图,可以实现CanDeactivate路由保护器。您将在此stackblitz中为“主页”页面找到一个示例。

导航到应用程序外部的链接应触发绑定到的事件处理程序window:beforeunload(在下面的HomeViewComponent中显示)。但是,其行为在Firefox(显示确认框)和Chrome(未显示确认框)中似乎有所不同。据我所知,该事件无法使用stackblitz进行测试。


在app.module中:

...
import { AppRoutingModule } from './app.routing.module';
import { DeactivateGuard } from './views/home/deactivate-guard';

@NgModule({
  imports: [ 
    AppRoutingModule, 
    ... 
  ],
  providers: [
    DeactivateGuard
  ],
  ...
})
Run Code Online (Sandbox Code Playgroud)

在app.routing.module中:

...
import { RouterModule } from '@angular/router';
import { DeactivateGuard } from './views/home/deactivate-guard';

@NgModule({
  imports: [
    RouterModule.forRoot([
      ...
      {
        path: 'home',
        component: HomeViewComponent,
        canDeactivate: [DeactivateGuard]
      },
      ...
    ])
  ],
  exports: [
    RouterModule,
  ],
  ... 
})
Run Code Online (Sandbox Code Playgroud)

在家庭/停用卫士中:

import { CanDeactivate } from '@angular/router';
import { HomeViewComponent } from './home.component';

export class DeactivateGuard implements CanDeactivate<HomeViewComponent> {

  canDeactivate(component: HomeViewComponent) {
    return component.canDeactivate();
  }
}
Run Code Online (Sandbox Code Playgroud)

在home.component中:

import { Component, HostListener } from '@angular/core';
...

@Component({
  ...
})
export class HomeViewComponent {

  @HostListener("window:beforeunload", ["$event"]) unloadHandler(event: Event) {
      event.returnValue = false;
  }

  canDeactivate() {
    return confirm("Do you want to leave?");
  }

  ...
}
Run Code Online (Sandbox Code Playgroud)


Js *_*Lim 0

我通过创建一个组件<a>、确认对话框组件和对话框服务来实现它

确认对话框

我正在使用角度材质

import { Component, Inject, Output, EventEmitter } from '@angular/core';
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material';

@Component({
  selector: 'confirm-dialog',
  templateUrl: './confirm-dialog.component.html',
})
export class ConfirmDialogComponent {

  constructor(
    public translate:TranslateService,
    public dialogRef: MatDialogRef<ConfirmDialogComponent>,
    @Inject(MAT_DIALOG_DATA) public data: any
    ) {
  }
  onClick(result): void {
    this.dialogRef.close(result);
  }

}
Run Code Online (Sandbox Code Playgroud)

html 文件

<h1 mat-dialog-title>{{data.title}}</h1>
<div mat-dialog-content>
    <h4 class="card-title">{{ data.message }}</h4>
</div>
<div mat-dialog-actions class="pull-right">
    <a *ngIf="data.confirm_link" class="btn btn-primary" mat-button tabindex="-1" href="{{ data.confirm_link }}" target="_blank" (click)="onClick(true)">{{ data.confirm_button }}</a>
    <button *ngIf="!data.confirm_link" class="btn btn-primary" mat-button tabindex="-1" (click)="onClick(true)"> {{ data.confirm_button }} </button>
    <button class="btn btn-info" mat-button tabindex="-1" (click)="onClick(false)">Cancel</button>
</div>
Run Code Online (Sandbox Code Playgroud)

服务

创建组件后,我希望可以轻松地从任何地方调用,因此为它创建一个服务

import { Injectable, OnDestroy} from "@angular/core";
import { Subject } from 'rxjs/Subject';
import { MatDialog } from '@angular/material';
import { ConfirmDialogComponent } from 'path/to/confirm-dialog/confirm-dialog.component';
import * as _ from 'lodash';

@Injectable()
export class ConfirmService implements OnDestroy{
    private subject = new Subject<any>();
    private message = 1;
    info: any;
    constructor(private dialog: MatDialog){
    }
    show(data: any){
        let dialogRef = this.dialog.open(ConfirmDialogComponent, {
          width: '500px',
          data: data,
        });

        dialogRef.afterClosed().subscribe(result => {
          this.subject.next(result);
        });
        return this.subject;
    }
    ngOnDestroy() {

    }
}
Run Code Online (Sandbox Code Playgroud)

自定义<a>元素

为了使其更容易在.html文件中使用,我为其创建了一个组件

import { Component, OnInit, Input } from '@angular/core';
import { ConfirmService } from 'path/to/service/confirm.service';

@Component({
  selector: 'a-external',
  templateUrl: './a-external.component.html',
})
export class AExternalComponent implements OnInit {
  @Input('href') href: string;
  @Input('class') classes: string;
  @Input('content') content: string;

  constructor(
    private confirmService:ConfirmService,
  ) { }

  ngOnInit() {
  }

  onAClick() {
    var dialog = this.confirmService.show({
      'title': 'Warning',
      'message': 'This will open a new tab',
      'confirm_button': 'open',
      'confirm_link': this.href, // if pass in the uri, will open in new tab
    });
    var subscription = dialog.subscribe((result) => {
      // if the result is true, means Confirm button is clicked
      // if the result is false, means Cancel button is clicked
      subscription.unsubscribe();
    });
  }
}
Run Code Online (Sandbox Code Playgroud)

confirm_link适用于打开新选项卡。如果没有该值,则只会触发对话框订阅结果。

而且html文件非常简单

<a href="javascript:" class="{{ classes }}" (click)="onAClick()">{{ content }}</a>
Run Code Online (Sandbox Code Playgroud)

使用它

<a-external [href]="http://www.foobar.com" [class]="'btn btn-info'" [content]="'The content inside a element'"></a-external>
Run Code Online (Sandbox Code Playgroud)