通用 Aurelia 对话框需要在脏和有效时启用保存

Generic Aurelia dialog needs Save enabled when dirty and valid

我正在尝试制作一个通用的、可重复使用的对话框,我们可以将其用于简单对象的基本数据输入——phone、电子邮件等

一般来说,我有一个助手 class 打开对话框,一个使用 aurelia-dialog 的通用对话框,然后是一个虚拟机,它被组合到包含所有表单编辑的主体的通用对话框中代码。

我遇到的问题是按钮在页脚中,它是对话框 vm 的一部分,但验证和脏指示器存在于构成正文的 vm 中。我想 disable/enable 基于正文 vm 中的指示器的保存按钮(在页脚中)。

对话框助手:

import {DialogService} from 'aurelia-dialog'
import {EditDialog} from 'app/resources/dialogs/edit-dialog'

export class DialogHelper {
    static inject = [DialogService] 

    constructor(dialogService){
        this.dialogService = dialogService
    }

    edit(title, view, item, showDelete){
        return this.dialogService.open({
             viewModel: EditDialog, 
             model: {view: view, 
                     item: item, 
                    title: title, 
               showDelete: showDelete }  })
    }
}

调用代码:

let email = {emailAddress: "123@gmail.com", emailType: "Personal"}
this.dialogHelper.edit("Email",'./pages/email-dialog',email,false)

EditDialog.js

import {DialogController} from 'aurelia-dialog'

export class EditDialog {
   static inject = [DialogController]

   showDelete = false

   constructor(dialogController){
        this.dialogController = dialogController
   }

   activate(options){
       this.options = options
   }

EditDialog.html

<template>
    <ai-dialog>
       <ai-dialog-header style="display:flex; justify-content:space-between">
          <span>Add/Edit ${options.title}</span><i style="cursor:pointer" class="fa fa-close" click.delegate="dialogController.cancel()"></i>
       </ai-dialog-header>

       <ai-dialog-body>
           <compose view-model.bind="options.view" model.bind="options.item" ></compose>
       </ai-dialog-body>

       <ai-dialog-footer style="display:flex;justify-content:space-between;">
        <span>
<!--Should have an if.bind here but not sure how since vm composed above knows details -->
            <button click.delegate="dialogController.ok({type:'save'})">Save</button>
            <button click.delegate="dialogController.cancel()">Cancel</button>
        </span>
        <button if.bind="options.showDelete" click.delegate="dialogController.ok({type:'delete'})"><i class="fa fa-trash"></i></button>
       </ai-dialog-footer>
   </ai-dialog>
</template>

邮箱-dialog.js

import {ValidationRules, ValidationController} from 'aurelia-validation'
import {computedFrom,NewInstance} from 'aurelia-framework'

export class EmailDialog {
    static inject = [NewInstance.of(ValidationController)]
    email = null

    constructor(validationController){
       this.validationController = validationController
       this.rule = ValidationRules.ensure(i => i.emailAddress)
                    .required()
                    .email()
                  .ensure(i => i.emailType)
                     .required()
                  .rules
    }

    activate(item){
       this.original = item
       this.email = JSON.parse(JSON.stringify(item))
    }

    @computedFrom('email.emailAddress', 'email.emailType')
    get canSave() {
        for(var prop in this.original){
            if(this.email[prop] != this.original[prop])
                 return false
        }

        return true
    }

}

我是否必须使用 EventAggregator 将消息传递给父级,或者是否有更好的方法通过某种绑定来处理这个问题? (或者是否有更好的方法一起解决这个问题?)

感谢您的帮助!

我不确定这是否适用于 aurelia-dialog,但这是我的建议:

您可以使用 view-model.ref="someIdentifier" 属性来获取 <compose> 元素的 view-model 的引用。 Cheat Sheet

此引用应该是 Compose class 和包含实际视图模型实例的 currentViewModel 属性(例如 EmailDialog)。

这是一个简化的要点示例:https://gist.run/?id=b23bf709d98b3bd3ae427852f104c890

将其应用于您的案例:

<ai-dialog-body>
    <compose view-model.ref="customVM" view-model.bind="options.view" model.bind="options.item" ></compose>
</ai-dialog-body>

<ai-dialog-footer style="display:flex;justify-content:space-between;">
    <span>
        <button if.bind="customVM.currentViewModel.canSave" click.delegate="dialogController.ok({type:'save'})">Save</button>
        <button click.delegate="dialogController.cancel()">Cancel</button>
    </span>
    <button if.bind="options.showDelete" click.delegate="dialogController.ok({type:'delete'})"><i class="fa fa-trash"></i></button>
</ai-dialog-footer>