我正在使用AureliaJS来构建动态表单场景,其中我有一个父表单,其中包含所需的总操作和多个子表单,这些表单根据用户输入进行更改。
这些孩子的形式本身只有两个具体的东西。他们的模型和他们的模型的验证规则。
所以我的问题是,父表单如何从当前子表单调用验证规则?从孩子我知道可以调用父母的视图模型。但是从父母那里,我怎样才能从孩子那里调用任何函数?
这个场景类似于有一个基类,它有一个方法,这个方法可以覆盖子类。
有什么建议吗?如果需要,我很乐意改变方法。
以下是一个示例:https://gist.run?id=1865041a15af60600cb7b538018bdccd
app.html
<template>
<span>This is an APP</span>
</p>
<compose view-model.bind="'parentForm'"></compose>
</template>
app.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';
}
}
的index.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>
parentForm.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';
}
}
答案 0 :(得分:1)
将一个函数调用绑定到子节点,以便您有一个从父节点调用它的句柄。我通常更喜欢直接绑定子组件而不是使用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!';
}
}
答案 1 :(得分: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.html 和 parent-form.js <而不是 parentForm.html 和 parentForm.js 。 / em>的。这不会改变你的代码中的东西,但你会遵循不错的javascript标准:)
直接绑定到字符串时,您不需要使用.bind
。例如,可以为view-model.bind="'parentForm'"
view-model="./parentForm"
希望这有帮助!
答案 2 :(得分:0)
立即想到的一件事是你可以在构造函数中将父模型注入你的子模型 - 注入的实例将是相同的,而不是新创建的实例。这样,您的父级可以定义一个方法,允许子级在父级上注册自己,然后父级可以调用子级在其选择时存在的任何方法。
这会在组件之间产生相当强烈的耦合,因此您需要考虑这是否可以接受。
如果不是,另一种解决问题的方法是使用event aggregator。父表单可以在聚合器上调度事件,子节点将是监听事件的订阅者。在这种情况下,根据您是否在一个页面上托管多个此类组合,您可能希望包含与该事件一起发送的表单的唯一标识符,并将该ID绑定到子组件,因此他们将知道只听他们父母的事件。