Angular-Material弹窗处理API的两种方式

553 阅读2分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

Angular-Material的弹窗在我近几个月的使用中,有了一些心得和经验,故作此记录。

弹窗的使用步骤是:触发弹窗的按钮/文字 => 显示弹窗 => 点击弹窗的按钮触发弹窗关闭 => 触发API

下面以我已经写好的弹窗作为例子

使用场景:点击弹窗,选择交货日期提交,通过比较交货日期和计划日期判断是否延期,如果延期需要提交理由,未延期则不需要。

弹窗的HTML

<h3 mat-dialog-title *ngIf="action == 'submit' || action == 'beyond'">填写交期</h3>
<div mat-dialog-content *ngIf="action == 'submit' || action == 'beyond'">
    <p>
        <span class="main_text">{{dateTitle}}:{{RealDate | date:"yyyy-MM-dd"}}</span>
    </p>
    <div>
        <span>{{dateLabel}}:</span>
        <mat-form-field class="mx24 time_picker">
            <input matInput [matDatepicker]="startPicker" [(ngModel)]="postDate" disabled>
            <mat-datepicker-toggle matSuffix [for]="startPicker"></mat-datepicker-toggle>
            <mat-datepicker #startPicker disabled="false"></mat-datepicker>
        </mat-form-field>
    </div>
    <div class="beyond">
        <span>延期理由:</span>
        <mat-form-field class="example-full-width">
            <input matInput placeholder="" value="" [(ngModel)]="form.comments">
        </mat-form-field>
    </div>
</div>
<div mat-dialog-actions class="button_box">
    <button mat-button (click)="onNoClick()">取消</button>
    <button *ngIf="action == 'submit'" mat-button (click)="submitDate()">提交</button>
    <button *ngIf="action == 'beyond'" mat-button (click)="beyondDate()">延期</button>
</div>

该HTML的逻辑是通过aciton传递参数,决定弹窗的标题、内容和按钮选择,不同的按钮对应不同的函数用于处理不同的API

两种函数处理API的两种方式

第一种:在弹窗内处理

思路:将参数传给弹窗后,在弹窗中将数据传给API进行处理,处理完成后关闭弹窗。

async beyondDate(): Promise<void> {

    const alertTitleText = '注意';
    const alertLabelText = '';
    const tipsData: any[] = [];
    const alertData: DialogData = {
      alertTitle: alertTitleText,
      alertLabel: alertLabelText,
      tips: tipsData,
    };
    const PostDate = this.general.formatTimeToDate(this.postDate);
    const RealDate = this.general.formatTimeToDate(this.RealDate);
    if (this.postDate == null || this.postDate === '') {
      tipsData.push('未输入' + this.dateLabel);
      this.openWarning(alertData);
    } else if (this.form.comments === '') {
      tipsData.push('请输入延期理由');
      this.openWarning(alertData);
    } else if (PostDate < RealDate) {
      tipsData.push(this.dateLabel + '需要大于' + this.dateTitle);
      this.openWarning(alertData);
    } else {
      const url = `/plan/beyondApply`;
      const res = await this.confSvc.sendPostCatch(url,
        {
          comments: `原预计成品入库日期:${this.general.formatTimeToDate(RealDate)},现更新预计入库日期:${this.general.formatTimeToDate(PostDate)},延期理由:${this.form.comments}`,
          plan_id: this.planId,
          order_id: this.orderId,
          time: this.general.formatTimeToDate(this.postDate),
          time_type: this.Status
        });
      this.confSvc.handleTip(res['msg']);
      this.confSvc.changeLoading(false);
      this.dialogRef.close();
    }
  }

该部分的逻辑顺序为:

  1. 获取弹窗的信息
  2. 将交货时间与计划时间相比
  3. 若交货时间>计划时间且未填延期理由,则弹窗(另一个弹窗)必须填写延期理由
  4. 若交货时间>计划时间且填了延期理由,则直接调用API
  5. 若交货时间<计划时间,则直接调用API 注意:这里的逻辑是处理完成后,直接调用API,处理完成后关闭弹窗。

第一种方式的优缺点

优点:代码逻辑清晰,从弹窗弹出到弹窗处理结束,一条直线。
缺点:

  1. 由于material弹窗独立于页面之外,所以无法使用加载图覆盖弹窗作为防抖。
  2. 弹窗使用的功能变多后,代码会变得更多,不宜维护

第二种方法:弹窗关闭后传值回页面

思路:将参数传给弹窗后,处理好数据保存为一个数组,在弹窗关闭后传回页面,在页面中进行API处理。

form = {
    comments: '',
    down: {
      type: '',
      value: ''
    }
  };
// 完结和保存
  async endOrder(): Promise<void> {
    const Form = this.form;
    const alertTitleText = '注意';
    const alertLabelText = '必须填写理由!';
    const tipsData: any[] = [];
    const alertData: DialogData = {
      alertTitle: alertTitleText,
      alertLabel: alertLabelText,
      tips: tipsData,
    };
    if (trim(this.form.comments) == '' || trim(this.form.comments) == null) {
      this.openWarning(alertData);
    } else {
      this.dialogRef.close({ Form });
    }
  }

其中this.dialogRef.close({ Form });代表弹窗关闭后将Form传回页面 处理API的页面ts部分:

// 强制完结
  async End(): Promise<void> {
    const _action = 'invalid';
    ……
    const dialogRef = this._matDialog.open(DialogOverviewExampleDialogComponent, {
      data: {
        action: _action,
        dateTitle: dateTitleText,
        dateLabel: dateLabelText,
        RealDate: RealDateText,
        order_status: this.orderData['order_status'],
        planId: this.planId,
        orderId: this.orderId,
        order_type: this.isType,
        userCnName: userCnName
      }
    });
    dialogRef.afterClosed().subscribe(async (res) => {
      if (res && res.Form) {
        this.confSvc.changeLoading(true);
        const userId = this.general.getUserId();
        const statusRes = await this.confSvc.sendPutCatch('order/check', {
          plan_id: this.planId,
          order_id: this.orderId,
          order_status: 100,
          is_compel: 1,
          comment_type: res.Form.down.value,
          comments: userCnName + '强制完结了该订单,原因:' + res.Form.down.type + ',备注:' + res.Form.comments,
          products_sku: this.orderData['products_sku'],
        });
        this.confSvc.handleTip(statusRes['msg']);
        this.fetchTableInfo();
        if (statusRes['code']) {
          this.orderData.order_status = 100;
          this.comments.getNoteList();
        }
        this.confSvc.changeLoading(false);
      }
    });
  }

其中dialogRef.afterClosed()代表弹窗结束后执行的动作。 subscriberxjs中一个发布订阅的模式,用于处理弹窗结束后返回的值,比较复杂,还在学习中,只能使用基本用法,等以后学习的差不多了再写一篇相关的博客。

第二种方式的优缺点

优点:

  1. 弹窗代码并不会很多,且可以对传参写一个对应的函数用于处理,这样所有的弹窗传参均可以通过一个函数整合为数组传回页面(该函数以后再写)
  2. 代码逻辑易于维护,每个按钮绑定的函数直接在当前页面即可维护,而不需要跳转到弹窗组件中一一寻找。 缺点:写法比较复杂,且牵扯到rxjssubscribe,上手难度偏高。