如何使用 @angular/cdk 使 NgbModal 可拖动

Posted

技术标签:

【中文标题】如何使用 @angular/cdk 使 NgbModal 可拖动【英文标题】:How to make NgbModal draggable with @angular/cdk 【发布时间】:2020-02-14 13:07:06 【问题描述】:

我在弄清楚如何使我的模态可拖动时遇到了一些困难。我有可重用的模式,它有自己的服务,被称为创建一个内部组件。

confirm.modal.service.ts

import  Injectable  from "@angular/core";
import  NgbModal  from "@ng-bootstrap/ng-bootstrap";
import  Observable, from, EMPTY, throwError  from "rxjs";
import  catchError, tap  from "rxjs/operators";

import  ConfirmModalComponent  from "./confirm-modal.component";

export interface ConfirmOptions 
    title: string;
    subtitle?: string;
    errorOnClose?: boolean;


@Injectable( providedIn: "root" )
export class ConfirmModalService 
    constructor(private modalService: NgbModal) 

    confirm(options: ConfirmOptions): Observable<boolean> 
        const modalRef = this.modalService.open(ConfirmModalComponent, 
            centered: true
        );
        modalRef.componentInstance.title = options.title || "Are you sure?";
        modalRef.componentInstance.subtitle = options.subtitle || null;

        return from(modalRef.result).pipe(
            tap(),
            catchError(err =>
                options.errorOnClose
                    ? throwError(err || "not confirmed")
                    : EMPTY
            )
        );
    

confirm.modal.module.ts

import  NgModule  from "@angular/core";
import  CommonModule  from "@angular/common";
import  DragDropModule  from "@angular/cdk/drag-drop";

import  ConfirmModalComponent  from "./confirm-modal.component";

@NgModule(
    imports: [
        CommonModule,
        DragDropModule
    ],
    declarations: [ConfirmModalComponent],
    exports: [ConfirmModalComponent]
)
export class ConfirmModalModule 

confirm.modal.component.ts

import  Component, Input  from "@angular/core";
import  NgbActiveModal  from "@ng-bootstrap/ng-bootstrap";

@Component(
    selector: "app-confirm-modal",
    templateUrl: "./confirm-modal.component.html",
    styleUrls: ["./confirm-modal.component.scss"]
)
export class ConfirmModalComponent 
    @Input() title: string;
    @Input() subtitle: string;

    constructor(public activeModal: NgbActiveModal) 

    public accept(): void 
        this.activeModal.close(true);
    

    public dismiss(): void 
        this.activeModal.close(false);
    

confirm.modal.component.html

<div class="modal-body">
    <div class="modal-body__header">
        <span> title </span>
    </div>
    <div *ngIf="subtitle" class="modal-body__text">
        <span> subtitle </span>
    </div>
    <div class="modal-body__button-row">
        <button class="btn btn-primary" (click)="accept()">Yes</button>
        <button class="btn btn-light" (click)="dismiss()">Cancel</button>
    </div>
</div>

所以我想用Angular built-in DragDropModule 使整个模态可拖动,因此我应该在元素内部添加cdkDragclass='modal-content',但我不知道如何通过当前设置实现这一点。 NgbModalOptions 提供仅添加类而不是属性指令的功能。 我知道 JQuery 可拖动有更简单的解决方案,但我想避免这种情况。

我曾考虑为每个页面使用@ViewChildren,但这似乎不是我的最佳解决方案。

感谢您的帮助!

【问题讨论】:

【参考方案1】:

只需将您的模式包装在一个容器中,然后按照documentation 将 cdkDragRootElement 添加到其中。当您从 component.ts 打开对话框时,您还必须将此类添加为选项。

<ng-template #content let-modal>
    <div class="you-custom-dialog-class"
      cdkDrag
      cdkDragRootElement=".your-custom-dialog-class">

      <div class="modal-header"></div>
      <div class="modal-body"></div>
      <div class="modal-footer"></div>
    </div>
</ng-template>

component.ts 的代码

const options: NgbModalOptions = 
    windowClass: 'your-custom-dialog-class'
;
this.modalService.open(this.content, options);

【讨论】:

不能完全正常工作:内部部分(类“cdk-drag”的div)被拖动。但是外部,带有“模态内容”类的部分仍然存在。它看起来像 div 的“alter-ego”... :) 所以,我做了以下调整: cdkDragRootElement=".modal-content"

以上是关于如何使用 @angular/cdk 使 NgbModal 可拖动的主要内容,如果未能解决你的问题,请参考以下文章

angular/cdk 简单拖动不适用于带有 ngFor 的 div

Angular CDK拖放 - 如何保持原始位置?

如何在运行时更改 Angular CDK 覆盖的 dir 属性?

如何更改 Angular CDK 拖放的 z-index?

Angular Cdk步进器,如何检测何时添加了新步骤

在带有 @angular/cdk-experimental 的 Angular Material 2 表中使用虚拟滚动