【问题标题】:Easy way to make a confirmation dialog in Angular?在 Angular 中进行确认对话框的简单方法?
【发布时间】:2017-05-31 17:56:29
【问题描述】:

是否有任何不那么复杂的方式在角度 2 中进行确认对话框,想法是单击一个项目,然后显示一个弹出窗口或模态以确认其删除,我从这里尝试了角度 2 模态 @987654321 @,但是如果您确认或取消它,我不知道该怎么做。 点击功能很好,唯一的问题是我不太清楚如何使用它。我也有另一个模态,它使用相同的插件,但我使用的不同。

this.modal.open(MyComponent);

我不想创建另一个组件只是为了显示一个确认框,这就是我问的原因。

【问题讨论】:

  • “简单的方法”是使用像你提到的 angular2-modal 之类的东西。否则,您将不得不自己构建一个,而我可能不会称其为简单方法。您是否在提供的链接上看到有显示用法的 plunker 示例:) embed.plnkr.co/mbPzd8
  • 我明白了,那么最好创建一个带有 2 个按钮的确认弹出窗口的组件,并在单击时在主组件中执行一个功能。在示例中,他使用 keyup 5 关闭对话框,我需要关闭它并调用一个函数。无论如何,我会尽量做到简单明了并发布结果
  • 还有其他模态框,可能有您可能想要的其他内置功能,但您的要求似乎并不太难,所以我想很多都适合您,但如果您喜欢,只需四处浏览并找到您喜欢的。以下是一些示例:npmjs.com/search?q=angular+2+modal 尝试一下,如果遇到问题,请返回 SO!快乐编码! :)

标签: angular confirmation


【解决方案1】:

方法一

一种简单的确认方法是使用本机浏览器确认警报。 模板可以有按钮或链接。

<button type=button class="btn btn-primary"  (click)="clickMethod('name')">Delete me</button>

组件方法可以如下所示。

clickMethod(name: string) {
  if(confirm("Are you sure to delete "+name)) {
    console.log("Implement delete functionality here");
  }
}

方法二

获得简单确认对话框的另一种方法是使用 angular bootstrap 组件,例如 ng-bootstrapngx-bootstrap。您可以简单地安装组件并使用模态组件。

  1. Examples of modals using ng-bootstrap
  2. Examples of modals using ngx-bootstrap

方法3

下面提供了另一种使用我在项目中实现的angular2/material 实现简单确认弹出窗口的方法。

app.module.ts

import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { ConfirmationDialog } from './confirm-dialog/confirmation-dialog';

@NgModule({
  imports: [
    ...
    FormsModule,
    ReactiveFormsModule
  ],
  declarations: [
    ...
    ConfirmationDialog
  ],
  providers: [ ... ],
  bootstrap: [ AppComponent ],
  entryComponents: [ConfirmationDialog]
})
export class AppModule { }

confirmation-dialog.ts

import { Component, Input } from '@angular/core';
import { MdDialog, MdDialogRef } from '@angular/material';

@Component({
  selector: 'confirm-dialog',
  templateUrl: '/app/confirm-dialog/confirmation-dialog.html',
})
export class ConfirmationDialog {
  constructor(public dialogRef: MdDialogRef<ConfirmationDialog>) {}

  public confirmMessage:string;
}

确认对话框.html

<h1 md-dialog-title>Confirm</h1>
<div md-dialog-content>{{confirmMessage}}</div>
<div md-dialog-actions>
  <button md-button style="color: #fff;background-color: #153961;" (click)="dialogRef.close(true)">Confirm</button>
  <button md-button (click)="dialogRef.close(false)">Cancel</button>
</div>

app.component.html

<button (click)="openConfirmationDialog()">Delete me</button>

app.component.ts

import { MdDialog, MdDialogRef } from '@angular/material';
import { ConfirmationDialog } from './confirm-dialog/confirmation-dialog';

@Component({
  moduleId: module.id,
  templateUrl: '/app/app.component.html',
  styleUrls: ['/app/main.css']
})

export class AppComponent implements AfterViewInit {
  dialogRef: MdDialogRef<ConfirmationDialog>;

  constructor(public dialog: MdDialog) {}

  openConfirmationDialog() {
    this.dialogRef = this.dialog.open(ConfirmationDialog, {
      disableClose: false
    });
    this.dialogRef.componentInstance.confirmMessage = "Are you sure you want to delete?"

    this.dialogRef.afterClosed().subscribe(result => {
      if(result) {
        // do confirmation actions
      }
      this.dialogRef = null;
    });
  }
}

index.html => 添加以下样式表

<link rel="stylesheet" href="node_modules/@angular/material/core/theming/prebuilt/indigo-pink.css">

【讨论】:

  • 我还必须从 @angular/platform-b​​rowser/animations 导入 BrowserAnimationsModule,从 @angular/material 导入 MaterialModule
  • 另外,对于我使用@import '~@angular/material/prebuilt-themes/deeppurple-amber.css'; 跟随this 的样式
  • 回到一年后,忘记添加解决了。目前我在一个大项目中,我选择了 matDialog,它是完整的、易于使用但功能强大的,它为您提供了一种简单的方法来在您的主要组件和对话框之间进行通信,从而允许许多新选项。如果有人遇到这个问题,我建议你试一试,它需要一些准备,但它是值得的,因为它可以完美运行
  • 这是否适用于回调函数?我没有尝试过代码,阅读它我只看到一个静态类型的回调,例如,如果你想做一个动态调用,比如按 ID 删除某些东西,你需要解析一个参数并在那里安装逻辑。
  • +1。这是一个非常好的例子,几乎可以开箱即用。对于最新版本,只需将 md 替换为 mat 并可能使用一些内置样式的按钮:mat-raised-button color="primary"
【解决方案2】:

您可以在函数中使用 window.confirm 并结合 if 条件

 delete(whatever:any){
    if(window.confirm('Are sure you want to delete this item ?')){
    //put your delete method logic here
   }
}

当您调用 delete 方法时,它会弹出一条确认消息,当您按下 ok 时,它将执行 if 条件中的所有逻辑。

【讨论】:

  • 您不必使用 window 关键字。
【解决方案3】:

我参加聚会已经很晚了,但这是另一个使用 的实现:https://stackblitz.com/edit/angular-confirmation-dialog

confirmation-dialog.service.ts

import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';

import { NgbModal } from '@ng-bootstrap/ng-bootstrap';

import { ConfirmationDialogComponent } from './confirmation-dialog.component';

@Injectable()
export class ConfirmationDialogService {

  constructor(private modalService: NgbModal) { }

  public confirm(
    title: string,
    message: string,
    btnOkText: string = 'OK',
    btnCancelText: string = 'Cancel',
    dialogSize: 'sm'|'lg' = 'sm'): Promise<boolean> {
    const modalRef = this.modalService.open(ConfirmationDialogComponent, { size: dialogSize });
    modalRef.componentInstance.title = title;
    modalRef.componentInstance.message = message;
    modalRef.componentInstance.btnOkText = btnOkText;
    modalRef.componentInstance.btnCancelText = btnCancelText;

    return modalRef.result;
  }

}

confirmation-dialog.component.ts

import { Component, Input, OnInit } from '@angular/core';
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';

@Component({
  selector: 'app-confirmation-dialog',
  templateUrl: './confirmation-dialog.component.html',
  styleUrls: ['./confirmation-dialog.component.scss'],
})
export class ConfirmationDialogComponent implements OnInit {

  @Input() title: string;
  @Input() message: string;
  @Input() btnOkText: string;
  @Input() btnCancelText: string;

  constructor(private activeModal: NgbActiveModal) { }

  ngOnInit() {
  }

  public decline() {
    this.activeModal.close(false);
  }

  public accept() {
    this.activeModal.close(true);
  }

  public dismiss() {
    this.activeModal.dismiss();
  }

}

confirmation-dialog.component.html

<div class="modal-header">
  <h4 class="modal-title">{{ title }}</h4>
    <button type="button" class="close" aria-label="Close" (click)="dismiss()">
      <span aria-hidden="true">&times;</span>
    </button>
  </div>
  <div class="modal-body">
    {{ message }}
  </div>
  <div class="modal-footer">
    <button type="button" class="btn btn-danger" (click)="decline()">{{ btnCancelText }}</button>
    <button type="button" class="btn btn-primary" (click)="accept()">{{ btnOkText }}</button>
  </div>

像这样使用对话框:

public openConfirmationDialog() {
    this.confirmationDialogService.confirm('Please confirm..', 'Do you really want to ... ?')
    .then((confirmed) => console.log('User confirmed:', confirmed))
    .catch(() => console.log('User dismissed the dialog (e.g., by using ESC, clicking the cross icon, or clicking outside the dialog)'));
  }

【讨论】:

  • 我已经按照上面的代码进行了操作,但是当我单击按钮时,弹出模式会出现几分之一秒并立即消失。你能帮我解决这个问题吗?
  • 链接的 StackBlitz 演示也会发生这种情况吗?
  • No.. 在 StackBlitz 中它工作正常。我已经在我的项目模板中复制了所有这些文件,我正面临这个问题
  • 好吧,如果没有更多信息,这很难(阅读:不可能)调试。
  • @tilo:看起来它只适用于 Angular 5。不适用于 Angular 4。更重要的是,他们在更高版本的 ng-bootstrap 中删除了 @Injectable()
【解决方案4】:

更新:添加了 Plunkr

我在所有论坛上都在寻找解决方案,但没有找到,因此找到了带有 Old School Javascript 回调函数的解决方案。 这是创建确认对话框并为 YESNO 点击事件设置回调函数的一种非常简单明了的方法。
我已经将 Bootstrap CSS 用于模态和带有 rxjs 主题的警报服务。

alert.component.html

        <div *ngIf="message.type == 'confirm'"  class="modal-body">
            <div class="row">
                <div class="col-md-12">
                    <h3 class="text-center">{{message.text}}</h3>
                </div>
            </div>
            <div class="row">
                <div class="col-md-12">
                    <p class="text-center">
                        <a (click)="message.noFn()">
                            <button class="btn btn-pm">No</button>
                        </a>
                        <a (click)="message.siFn()">
                            <button  class="btn btn-sc" >Yes</button>
                        </a>
                    </p>
                </div>
            </div>
         </div>

alert.component.ts

export class AlertComponent {
    message: any;
    constructor(
      public router: Router, 
      private route: ActivatedRoute, 
      private alertService: AlertService,
   ) { }
   ngOnInit() {
    //this function waits for a message from alert service, it gets 
    //triggered when we call this from any other component
    this.alertService.getMessage().subscribe(message => {
        this.message = message;
    });
}

最重要的部分在这里alert.service.ts

     import { Injectable } from '@angular/core'; 
     import { Router, NavigationStart } from '@angular/router'; 
     import { Observable } from 'rxjs'; 
     import { Subject } from 'rxjs/Subject';
     @Injectable() export class AlertService {
          private subject = new Subject<any>();
          constructor(){}
          confirm(message: string,siFn:()=>void,noFn:()=>void){
            this.setConfirmation(message,siFn,noFn);
          }
          setConfirmation(message: string,siFn:()=>void,noFn:()=>void) {
            let that = this;
            this.subject.next({ type: "confirm",
                        text: message,
                        siFn:
                        function(){
                            that.subject.next(); //this will close the modal
                            siFn();
                        },
                        noFn:function(){
                            that.subject.next();
                            noFn();
                        }
                     });

                 }

          getMessage(): Observable<any> {
             return this.subject.asObservable();
          }
       }

从任何组件调用函数

this.alertService.confirm("You sure Bro?",function(){
    //ACTION: Do this If user says YES
},function(){
    //ACTION: Do this if user says NO
})

Plunkr https://embed.plnkr.co/vWBT2nWmtsXff0MXMKdd/

【讨论】:

  • 嗨。我正在寻找类似的东西..但是上面的代码对我不起作用。没有显示模式,console.tanks 中也没有错误
  • 嗨 Mrpi,你能确定你是否有 Bootstrap css 吗?现在,如果您想测试 Modal 的外观,请删除 ng-if 并检查。
  • 它工作。谢谢。垂直定位到中心怎么样?
  • 你需要执行一些 JS 计算才能垂直完成,不能单独通过 CSS 完成。但是对于 Horizo​​ntally margin: 0 auto 就像一个魅力!
  • @NasiruddinSaiyed:你能告诉我要安装什么模块吗?我收到警告:./node_modules/@ng-bootstrap/ng-bootstrap/datepicker/datepicker-i18n.js 32:39-56 中的警告“在'@angular/common'中找不到导出'getLocaleDayNames'
【解决方案5】:

您可以使用 sweetalert:https://sweetalert.js.org/guides/

npm install sweetalert --save

然后,只需将其导入您的应用程序:

import swal from 'sweetalert';

如果你传递两个参数,第一个是模态框的标题,第二个是文本。

swal("Here's the title!", "...and here's the text!");

【讨论】:

    【解决方案6】:

    这是使用 javascript 的本机确认功能和自定义 Angular 指令的一个稍微不同的方法。它超级灵活且非常轻巧:

    用法:

    <button (hrsAreYouSure) (then)="confirm(arg1)" (else)="cancel(arg2)">
      This will execute confirm if user presses Ok on the confirmation dialog, or cancel if they
      hit Cancel
    </button>
    

    指令:

    import {Directive, ElementRef, EventEmitter, Inject, OnInit, Output} from '@angular/core';
    
    @Directive({
      selector: '[hrsAreYouSure]'
    })
    
    export class AreYouSureDirective implements OnInit {
    
      @Output() then = new EventEmitter<boolean>();
      @Output() else = new EventEmitter<boolean>();
    
      constructor(@Inject(ElementRef) private element: ElementRef) { }
    
      ngOnInit(): void {
        const directive = this;
        this.element.nativeElement.onclick = function() {
          const result = confirm('Are you sure?');
          if (result) {
            directive.then.emit(true);
          } else {
            directive.else.emit(true);
          }
        };
      }
    }
    

    【讨论】:

    • Chrome 要求我删除按钮中 hrsAreYouSure 周围的括号,否则它将不起作用。
    • 另外,如果您在对话框打开时按 Enter 键,您正在确认这是否是您的意图。
    【解决方案7】:

    为答案添加更多选项。

    你可以使用npm i sweetalert2

    不要忘记将样式添加到您的angular.json

    "styles": [
             ...
              "node_modules/sweetalert2/src/sweetalert2.scss"
              ]
    

    然后直接导入,

    // ES6 Modules or TypeScript
    import Swal from 'sweetalert2'
    
    
    // CommonJS
    const Swal = require('sweetalert2')
    

    Boom,你准备好了。

    Swal.fire({
      title: 'Are you sure?',
      text: 'You will not be able to recover this imaginary file!',
      icon: 'warning',
      showCancelButton: true,
      confirmButtonText: 'Yes, delete it!',
      cancelButtonText: 'No, keep it'
    }).then((result) => {
      if (result.value) {
        Swal.fire(
          'Deleted!',
          'Your imaginary file has been deleted.',
          'success'
        )
      // For more information about handling dismissals please visit
      // https://sweetalert2.github.io/#handling-dismissals
      } else if (result.dismiss === Swal.DismissReason.cancel) {
        Swal.fire(
          'Cancelled',
          'Your imaginary file is safe :)',
          'error'
        )
      }
    })
    

    更多信息:- https://www.npmjs.com/package/sweetalert2

    我希望这对某人有所帮助。

    谢谢。

    【讨论】:

      【解决方案8】:

      为了在多模块应用程序中重用单个确认对话框实现,该对话框必须在单独的模块中实现。这是使用 Material Design 和 FxFlex 实现此目的的一种方法,尽管这两种方法都可以缩减或替换。

      首先是共享模块(./app.module.ts):

      import {NgModule} from '@angular/core';
      import {CommonModule} from '@angular/common';
      import {MatDialogModule, MatSelectModule} from '@angular/material';
      import {ConfirmationDlgComponent} from './confirmation-dlg.component';
      import {FlexLayoutModule} from '@angular/flex-layout';
      
      @NgModule({
         imports: [
            CommonModule,
            FlexLayoutModule,
            MatDialogModule
         ],
         declarations: [
            ConfirmationDlgComponent
         ],
         exports: [
            ConfirmationDlgComponent
         ],
         entryComponents: [ConfirmationDlgComponent]
      })
      
      export class SharedModule {
      }
      

      还有对话框组件(./confirmation-dlg.component.ts):

      import {Component, Inject} from '@angular/core';
      import {MAT_DIALOG_DATA} from '@angular/material';
      
      @Component({
         selector: 'app-confirmation-dlg',
         template: `
            <div fxLayoutAlign="space-around" class="title colors" mat-dialog-title>{{data.title}}</div>
            <div class="msg" mat-dialog-content>
               {{data.msg}}
            </div>
            <a href="#"></a>
            <mat-dialog-actions fxLayoutAlign="space-around">
               <button mat-button [mat-dialog-close]="false" class="colors">No</button>
               <button mat-button [mat-dialog-close]="true" class="colors">Yes</button>
            </mat-dialog-actions>`,
         styles: [`
            .title {font-size: large;}
            .msg {font-size: medium;}
            .colors {color: white; background-color: #3f51b5;}
            button {flex-basis: 60px;}
         `]
      })
      export class ConfirmationDlgComponent {
         constructor(@Inject(MAT_DIALOG_DATA) public data: any) {}
      }
      

      然后我们可以在另一个模块中使用它:

      import {FlexLayoutModule} from '@angular/flex-layout';
      import {NgModule} from '@angular/core';
      import {GeneralComponent} from './general/general.component';
      import {NgbModule} from '@ng-bootstrap/ng-bootstrap';
      import {CommonModule} from '@angular/common';
      import {MaterialModule} from '../../material.module';
      
      @NgModule({
         declarations: [
            GeneralComponent
         ],
         imports: [
            FlexLayoutModule,
            MaterialModule,
            CommonModule,
            NgbModule.forRoot()
         ],
         providers: []
      })
      export class SystemAdminModule {}
      

      组件的点击处理程序使用对话框:

      import {Component} from '@angular/core';
      import {ConfirmationDlgComponent} from '../../../shared/confirmation-dlg.component';
      import {MatDialog} from '@angular/material';
      
      @Component({
         selector: 'app-general',
         templateUrl: './general.component.html',
         styleUrls: ['./general.component.css']
      })
      export class GeneralComponent {
      
         constructor(private dialog: MatDialog) {}
      
         onWhateverClick() {
            const dlg = this.dialog.open(ConfirmationDlgComponent, {
               data: {title: 'Confirm Whatever', msg: 'Are you sure you want to whatever?'}
            });
      
            dlg.afterClosed().subscribe((whatever: boolean) => {
               if (whatever) {
                  this.whatever();
               }
            });
         }
      
         whatever() {
            console.log('Do whatever');
         }
      }
      

      像您一样使用this.modal.open(MyComponent); 不会返回您可以订阅其事件的对象,这就是您无法让它做某事的原因。此代码创建并打开一个我们可以订阅其事件的对话框。

      如果你精简 css 和 html,这确实是一个简单的组件,但是你自己编写它可以让你控制它的设计和布局,而预先编写的组件需要更重量级才能让你控制。

      【讨论】:

      • 不错的答案,但我认为将组件放在单独的共享模块中会增加不必要的复杂性。
      【解决方案9】:

      根据您的特定项目需求制作功能和特性总是更好,但我们通常没有时间编写我们想要编写的所有小东西。如果您不想自己编写代码,可以使用 npm 包@costlydeveloper/ngx-awesome-popup 轻松完成。

      您可以通过这种方式仅从包中实现 Confirm Box 模块:

      在您的 app.module.ts 中

          import {NgModule} from '@angular/core';
          import {BrowserModule} from '@angular/platform-browser';
          import {AppComponent} from './app.component';
          
          // Import your library
          import {ConfirmBoxConfigModule, NgxAwesomePopupModule} from '@costlydeveloper/ngx-awesome-popup';
          
          
          @NgModule({
              declarations: [
                  AppComponent
              ],
              imports     : [
                  BrowserModule,
          
                  // Import popup and confirm box module
                  NgxAwesomePopupModule.forRoot(),
                  ConfirmBoxConfigModule.forRoot()
              ],
              providers   : [],
              bootstrap   : [AppComponent]
          })
          export class AppModule {
          }
      

      然后通过这种方法在打字稿代码中的任何地方唤起它:

           confirmBox() {
                  const confirmBox = new ConfirmBoxInitializer();
                  confirmBox.setTitle('Are you sure?');
                  confirmBox.setMessage('Confirm to delete user: John Doe!');
                  // Set button labels, the first argument for the confirmation button, and the second one for the decline button.
                  confirmBox.setButtonLabels('YES', 'NO');
                  
                  confirmBox.setConfig({
                      DisableIcon: true, // optional
                      AllowHTMLMessage: false, // optional
                      ButtonPosition: 'center', // optional
                      // Evoke the confirmation box with predefined types.
                      LayoutType: DialogLayoutDisplay.DANGER // SUCCESS | INFO | NONE | DANGER | WARNING
                  });
                  
                  // Simply evoke the popup and listen which button is clicked.
                  const subscription = confirmBox.openConfirmBox$().subscribe(resp => {
                      // IConfirmBoxPublicResponse
                      console.log('ConfirmBox button response: ', resp);
                      subscription.unsubscribe();
                  });
              }
      

      得到这样的结果:

      【讨论】:

        猜你喜欢
        • 2021-05-18
        • 2020-06-04
        • 2019-03-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多