3

我正在使用 AureliaJS 构建一个动态表单场景,其中我有一个父表单,其中包含所需的总操作和多个子表单,这些表单根据用户输入进行更改。

这些孩子的形式本身只有两个特定的东西。他们的模型和模型的验证规则。

所以我的问题是,父表单如何从当前子表单调用验证规则?从孩子我知道可以调用父母的视图模型。但是从父母那里,我怎样才能从孩子那里调用任何功能呢?

该场景类似于具有一个基类,该基类具有一种方法,并且该方法可以覆盖子类。

有什么建议吗?如果需要,我很高兴改变方法。

这是一个例子:https ://gist.run?id=1865041a15af60600cb7b538018bdccd

应用程序.html

<template>
  <span>This is an APP</span>
  </p>
  <compose view-model.bind="'parentForm'"></compose>
</template>

应用程序.js

import { autoinject } from 'aurelia-framework';

@autoinject
export class App {

}

childForm1.html

<template>
  <label> Price : </label>
  <input value.bind="model.data.price">
  <p/>
  <label> VAT : </label>
  <input value.bind="model.data.vat">
  <p/>
</template>

childForm1.js

import { autoinject } from 'aurelia-framework';

@autoinject
export class ChildForm1 {

  activate(model)
  {
    this.model = model;
  }

 validateRules (){

     if(this.model.data.price != '' && this.model.data.vat == '' )
      this.model.validateMessage = 'VAT is mandatory';
 }
}

childForm2.html

<template>
  <label>Address : </label>
  <input value.bind="model.data.address">
  <p/>
  <label>Phone : </label>
  <input value.bind="model.data.phone">
  <p/>
</template>

childForm2.js

import { autoinject } from 'aurelia-framework';

@autoinject
export class ChildForm2 {

  activate(model)
  {
    this.model = model;
  }

 validateRules (){

   if(this.model.data.phone != '' && this.model.data.address == '' )
      this.model.validateMessage = 'Address is mandatory';
 }
}

索引.html

<!doctype html>
<html>
  <head>
    <title>Aurelia</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
  </head>
  <body aurelia-app>
    <h1>Loading...</h1>

    <script src="https://jdanyow.github.io/rjs-bundle/node_modules/requirejs/require.js"></script>
    <script src="https://jdanyow.github.io/rjs-bundle/config.js"></script>
    <script src="https://jdanyow.github.io/rjs-bundle/bundles/aurelia.js"></script>
    <script src="https://jdanyow.github.io/rjs-bundle/bundles/babel.js"></script>
    <script>
      require(['aurelia-bootstrapper']);
    </script>
  </body>
</html>

父窗体.html

<template>
  <button click.delegate="changeChildForm1()">Change Child Form 1</button>
  <button click.delegate="changeChildForm2()">Change Child Form 2</button>
  <p/>
  <p/>
  <form>
    <label>User : </label>
    <input value.bind="model.data.user">
    <p/>
    <compose view-model.bind="childFormVM" model.bind="model"></compose>
    <button click.delegate="save()">Save</button>
    <p/>
    <span> Validation Message :  ${model.validateMessage}</span>
  </form>
   <p/>
  <span>Price : ${model.data.price}</span><p/>
  <span>Vat : ${model.data.vat}</span><p/>
  <span>Phone : ${model.data.phone}</span><p/>
  <span>Address : ${model.data.address}</span><p/>
</template>

parentForm.js

import { autoinject } from 'aurelia-framework';

@autoinject
export class ParentForm {
  model = {
   validateMessage : '', 
   data : {
    user : 'My Name'
   }
 };

 childFormVM = 'childForm1';

 validateMessage = '';

 changeChildForm1() {

   this.childFormVM = 'childForm1';
 }

  changeChildForm2() {

   this.childFormVM = 'childForm2';
 }

 save(){
   this.validateRules();
   // How to call the validation rules from child ?
 }

 validateRules (){

   this.model.validateMessage = 'Validate by parent';
 }
}
4

3 回答 3

3

将函数调用绑定到子级,以便您拥有从父级调用它的句柄。我通常更喜欢直接绑定子组件而不是使用compose,但是您可以通过传递复杂的模型对象而不是仅传递模型并将绑定函数作为模型属性之一传递来使其与 compose 一起使用。

父视图模型:

class Parent {
  model = {};
  child1Validate = null;

  changeChildForm1() {
    if (typeof this.child1Validate === 'function') {
      // the binding was successful; proceed with function call
      let result = this.child1Validate();
      console.log(result);
    }
  }
}

父视图:

<my-child1 model="parentModel" go-validate="child1Validate"></my-child1>

子视图模型:

class MyChild1 {
  @bindable model;
  @bindable goValidate;
  bind() {
    // bind the child function to the parent that instantiates the child
    this.goValidate = this.runValidation.bind(this);
  }
  runValidation() {
    // do the validation and pass result to parent...
    return 'Success!';
  }
}
于 2017-07-05T12:38:04.633 回答
1

你可以这样做:

父form.html

<compose view-model.bind="childFormVM" view-model.ref="childFormInstance" model.bind="model"></compose>

父form.js

save() {
  this.childFormInstance.currentViewModel.validateRules();
}

有用的笔记

<compose>在必要时使用。例如,在 app.html 中,您应该替换<compose>为:

<require from="parentForm"></require>
    
<parent-form></parent-form>

使用 kebab-case 而不是 camel-case 来命名文件。例如,使用parent-form.htmlparent-form.js代替parentForm.htmlparentForm.js。这不会改变您的代码中的任何内容,但您将遵循良好的 javascript 标准 :)

直接绑定到字符串时,您不需要使用.bind. 例如,view-model.bind="'parentForm'"可以替换为view-model="./parentForm"

希望这可以帮助!

于 2017-07-05T12:38:51.910 回答
0

立即想到的一件事是,您可以在构造函数中将父模型注入到子模型中——注入的实例将是相同的,而不是新创建的。这样,您的父级可以定义一个允许子级在父级上注册自己的方法,然后父级可以调用子级选择时存在的任何方法。

但是,这会在组件之间产生相当强的耦合,因此您需要考虑您是否可以接受。

如果不是,另一种解决问题的方法是使用事件聚合器。父表单可以在聚合器上发送事件,子表单将成为监听事件的订阅者。在这种情况下,根据您是否在一个页面上托管多个此类组合,您可能希望包含与事件一起发送的表单的唯一标识符并将该 ID 绑定到子组件,以便他们知道只听他们父母的事件。

于 2017-07-05T11:03:36.753 回答