Angular2:使用浏览器返回事件

时间:2017-03-07 18:18:43

标签: angular ng-bootstrap

我的Angular2应用使用ng-bootstrap modal来详细显示一些结果图表。出于这个原因,我将模态调整为几乎全屏(仅剩margin: 20px)。这会导致某些用户使用浏览器后退按钮而不是页面右上角或底部的关闭按钮。

我现在尝试的是取消默认的浏览器返回事件,并在调用事件时关闭模式。

我使用here中的一些代码作为代码库来监听浏览器事件并将其扩展为一些东西:

import { PlatformLocation } from '@angular/common'

(...)

modalRef: NgbModalRef;

constructor(location: PlatformLocation) {

    location.onPopState(() => {

        console.log('pressed back!');

        // example for a simple check if modal is opened
        if(this.modalRef !== undefined) 
        {
            console.log('modal is opened - cancel default browser event and close modal');
            // TODO: cancel the default event

            // close modal
            this.modalRef.close();
        } 
        else 
        {
            console.log('modal is not opened - default browser event');
        }
    });
}

(...)
// some code to open the modal and store the reference to this.modalRef

问题在于我不知道如何以及是否可以取消默认的后退事件。

location.onPopState((event) => {

    event.preventDefault();

});

这实际上不起作用。 this solution也是如此。 也许我可以插入一些"假的"打开模态时的历史堆栈?!

对于AngularJS 1.x,它似乎确实有效:https://stackoverflow.com/a/33454993/3623608

5 个答案:

答案 0 :(得分:7)

我实际上通过在打开模态时插入一些“假”历史状态来解决我的问题。 模态打开和模态关闭的功能如下所示:

<div ng-click="MyFunction()"></div>

open()和getDismissReason()函数从https://docs.angularjs.org/guide/services“Modal with default options”复制。我添加的重要部分是在模态打开时推动新历史状态,并在“正常”模态关闭时回溯历史。当我们返回浏览器后退按钮时,不会调用此功能,我们会自动返回历史记录。

要确保在历史回溯事件中关闭模态,您需要以下行:

modalRef: NgbModalRef;

open(content: NgbModal) {
    this.modalRef = this.modalService.open(content);

    // push new state to history
    history.pushState(null, null, 'modalOpened');

    this.modalRef.result.then((result) => {
        this.closeResult = `Closed with: ${result}`;
    }, (reason) => {
        this.closeResult = `Dismissed ${this.getDismissReason(reason)}`;
    });
}

private getDismissReason(reason: any): string {
    // go back in history if the modal is closed normal (ESC, backdrop click, cross click, close click)
    history.back();

    if (reason === ModalDismissReasons.ESC) {
        return 'by pressing ESC';
    } else if (reason === ModalDismissReasons.BACKDROP_CLICK) {
        return 'by clicking on a backdrop';
    } else {
        return  `with: ${reason}`;
    }
}

结论:当打开模态时,我们会推送新的历史记录状态(例如,使用当前页面)。如果模态正常关闭(使用ESC,关闭按钮,......),则手动触发历史回溯事件(我们不希望堆叠历史状态)。如果历史回复事件是由浏览器触发的,我们只需要关闭模式(如果它已打开)。推送的历史堆栈确保我们保持在同一页面上。

限制:添加新的历史记录堆栈并返回历史记录也提供了在历史记录中前进的机会(在关闭模式之后)。这不是理想的行为。

答案 1 :(得分:1)

On Destroy Lifecycle hook将解决您的问题。

export class AppComponent implements OnDestroy{
  @ViewChild('childModal') childModal :CommonModalComponent;
  constructor(private viewContainerRef: ViewContainerRef) {
  }
   ngOnDestroy() {
    this.childModal.hide();
  }

}

<强> LIVE DEMO

答案 2 :(得分:1)

据我所知,我认为OP的重点是答案:

“我现在正在尝试取消默认的浏览器返回事件”

...是你无法取消后退按钮事件。据我所知,这是浏览器可用性限制。

答案 3 :(得分:0)

ng-bootstrap模式,现在有dismissAll()

https://ng-bootstrap.github.io/#/components/modal/api#NgbModal

当ng-router检测到更改(包括浏览器后退)时,您可以使用route-guard关闭所有打开的模式

export class NgbModalDismissAllGuard implements CanActivateChild {
  constructor(private modalService: NgbModal) {}

  canActivateChild(
    route: ActivatedRouteSnapshot,
    state: RouterStateSnapshot
  ): Observable<boolean> | Promise<boolean> | boolean {
    if (this.modalService.hasOpenModals()) this.modalService.dismissAll();
    return true;
  }
}

和在路由器配置中。.

const routes: Routes = [
  { 
    path: '', 
    canActivateChild: [NgbModalDismissAllGuard], 
    loadChildren: () => import('./Custom.Module').then(m => m.CustomModule) 
  }
];

答案 4 :(得分:0)

您需要将此代码添加到对话框组件中。

import { PlatformLocation } from '@angular/common';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
...

constructor(
    private platformLocation: PlatformLocation ,
    private modalService: NgbModal) {

    // closes modal when back button is clicked
    platformLocation.onPopState(() => this.modalService.dismissAll());
}