web-dev-qa-db-ja.com

Angular 5ルート変更の前にイベントを追加

ユーザーが<a href="...">リンクをクリックする前に、警告ダイアログを追加したいと思います。

<a>リンクには2種類あります

  1. Angular scope <a routerLink="/path/to/dest">内でリダイレクト
  2. Angular app <a href="http://www.somewhere.com" target="_blank">の外部にリダイレクトする

ユーザーがAngularスコープの外に出ようとしたときに警告ボックスを表示できるようにしたい

Alert dialog

すべての<a>クリックイベントに適用したい(事前フックのようなもの)

これを達成する方法はありますか?

7
Js Lim

<a>のコンポーネント、確認ダイアログコンポーネント、およびダイアログのサービスを作成することで実現します

確認ダイアログ

私は Angular Material を使用しています

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);
  }

}

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>

サービス

コンポーネントが作成されたら、どこからでも簡単に呼び出せるようにするため、そのためのサービスを作成します

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() {

    }
}

カスタム<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();
    });
  }
}

confirm_linkは、新しいタブを開く場合にのみ適用されます。値を指定しないと、ダイアログサブスクリプションの結果がトリガーされます。

そして、htmlファイルは非常に簡単です

<a href="javascript:" class="{{ classes }}" (click)="onAClick()">{{ content }}</a>

それを使用するには

<a-external [href]="http://www.foobar.com" [class]="'btn btn-info'" [content]="'The content inside a element'"></a-external>
0
Js Lim

Angularアプリケーションの他のビューへのリンクについては、 CanDeactivateルートガード を実装できます。例は-にあります。 this 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
  ],
  ...
})

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,
  ],
  ... 
})

Home/deactivate-guardの場合:

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

export class DeactivateGuard implements CanDeactivate<HomeViewComponent> {

  canDeactivate(component: HomeViewComponent) {
    return component.canDeactivate();
  }
}

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?");
  }

  ...
}
5
ConnorsFan

so Angularは、特定の条件に基づいてルートをアクティブにするかどうかを確認するcanActivateを提供します。

const routes: Routes = [
    {path: '/some-path', canActivate:[AuthGuard]}
];

CanActivateサービス

import { Injectable } from '@angular/core';
import { CanActivate, CanActivateChild } from '@angular/router';

@Injectable()
export class AuthGuard implements CanActivate, CanActivateChild {

  canActivate() {
    //ask if he really wants to route.
    console.log('i am checking to see if you are logged ')
    return true;
  }

  canActivateChild() {
    console.log('checking child route access');
    return true;
  }

}

CanActivateでは、URLにルーティングするかどうかを尋ねる一般的なモデルを表示できます。それに基づいて、どのリンクでリンクを保持できるかを制御できます。アンカータグからのものであろうと他のものからであろうと、すべてのルーティングのロジックを記述することもできます。

2
manish kumar

条件をチェックし、選択に応じてクリックしたURLにリダイレクトするかどうかを決定するルートガードを実装できます。

angular cliをフォローしている場合は、次を実行してルートガードをインストールできます。

ng g guard my-new-guard

App.module.tsのガードファイルをインポートし、プロバイダー配列に追加します。ルーティングファイルで、条件を確認するパスにルートガードを追加します。お気に入り :

const appRoutes: Routes = [
    {path: '/your-path', canActivate: [route-guard]}
];

ルートガードファイルでは、次のようなロジックを実装できます。

import { Injectable } from '@angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot} from '@angular/router';
import { Observable } from 'rxjs/Observable';

@Injectable()
export class AuthGuardGuard implements CanActivate {
    canActivate(
        next: ActivatedRouteSnapshot,
        state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {

            if(!state.url.startsWith('/')){
               // I have check here for starting single slash for all your angular local routes. You can also check for http or https whichever you want according to your need
               // here you can trigger your modal pop-up on its 'OK' button return true to redirect to the url
               return true;   // or return false on 'Cancel' button of modal pop-up for cancelling route if condition doesn't fullfill
            }
    }
}
0
Mohsin Hasan

.tsファイル

ngAfterViewInit() {
    var aElements = this._elementRef.nativeElement.querySelectorAll('a');
    var aElementsLen = aElements.length;
    console.log('aElements==========>', aElements);
    for(let i=0; i< aElementsLen; i++){
        console.log('aElements[i]==========>', aElements[i]);
        aElements[i].addEventListener('click',  function(e){
            e.preventDefault();
            //return true; // If Redirect inside of Angular app
            return false; // Redirect outside of Angular app and show popup
        });
    }
}

Plnkrリンク

0
vijayliebe

これを試して

HTMLで

<a role="button" (click)="yourfunc()">

あなたのtsで

yourfunc(){

   alert('navigate')

  window.location.href='http://www.somewhere.com';

  // your code to navigate

  }
0
Arun Kumaresh