Aurelia 验证问题

Issue with Aurelia validation

我尝试动态添加验证,但验证方法 returns 仅出现第一个错误。 我的目标是使用来自服务器的所有验证规则解析 json 并动态添加验证。

我的html:

<input id="myInput1" value.bind="myInput1 & validateOnChangeOrBlur" errors.bind="myInput1Errors"/>
<input id="myInput2" value.bind="myInput2 & validateOnChangeOrBlur" errors.bind="myInput2Errors"/>
<button click.delegate='validate()'>validate</button>

<ul if.bind="controller.errors">
  <li repeat.for="error of controller.errors">
    ${error.message}
  </li>
</ul>

我的.ts:

attached() {
      let rules = [];
      //my real code is a for loop for adding dynamically
      rules.push(ValidationRules
                        .ensure('myInput1')
                        .required()
                        .rules[0]);
      rules.push(ValidationRules
                        .ensure('myInput2')
                        .required()
                        .rules[0]);
     this.controller.addObject(this, rules);
    }

 validate() {
          this.controller.validate()
                .then(result => {
                    if (result.valid) {
                        //
                    } else {
                       //
                    }
                });
        }

当我模糊(选项卡导航)时,验证方法正确显示错误,一个接一个地堆叠它们。 当我调用验证时,它只显示第一个。

但是,如果我静态地执行此操作,它会起作用(模糊和验证):

ValidationRules
            .ensure('myInput1')
            .required()
            .ensure('myInput2')
            .required()
            .on(this);

那么动态添加有什么问题呢?

我为此创建了一个 gistrun:https://gist.run/?id=c60ee8a86c9c473b97e930e117fd68df

谢谢。

通过动态创建它们的方式,您无意中创建了 sequenced 规则。由于您的问题,我还发现了一个非常微妙的错误。我将在下面解释。首先,有两种可能的解决方案:

解决方案 1

使 rules 成为数组的数组,并添加嵌套的数组项。

let rules = [[]];
//my real code is a for loop for adding dynamically
rules[0].push(ValidationRules
                  .ensure('myInput1')
                  .required()
                  .rules[0][0]);
rules[0].push(ValidationRules
                  .ensure('myInput2')
                  .required()
                  .rules[0][0]);
this.controller.addObject(this, rules);

解决方案 2

使用Rules.set(这仍然是"wrong",我将在下面解释它为什么有效)

let rules = [];
//my real code is a for loop for adding dynamically
rules.push(ValidationRules
                  .ensure('myInput1')
                  .required()
                  .rules[0]);
rules.push(ValidationRules
                  .ensure('myInput2')
                  .required()
                  .rules[0]);
Rules.set(this, rules);

原因

外部数组是 规则序列 的数组(单独也是数组)。内部数组是该序列 .

规则的列表

通过将 .rules[0] 添加到数组,您最终得到一个规则序列数组,每个规则序列都有一个规则:

rules[0][0]
rules[1][0]
rules[2][0]
rules[3][0]

然而,当您将调用链接到同一个规则构建器时,它会在内部做正确的事情,.rules 将是一个包含所有单独规则的序列的数组:

rules[0][0]
rules[0][1]
rules[0][2]
rules[0][3]

序列

序列允许您按特定顺序执行规则,其中每个连续序列仅在所有先前序列评估为有效时才被评估。因此,您创建的序列实际上按预期运行:第一个 属性 结果无效,其余未评估。

仅供参考,"normal" 创建顺序规则的方法是在规则生成器上使用 .then()。只要您不使用 .then(),您将始终拥有索引为 0.

单个 序列

如何存储规则

当您使用 controller.addObject(this, rules) 时,规则存储在该控制器 上的地图 中。只有那个控制器会知道这些规则。

另一方面,Rules.set() 将规则存储在您提供的对象原型上的元数据对象 (属性 __rules__) 中。终结器 .on() 以相同的方式存储它们(它只是调用 Rules.set())。这使得规则对所有控制器有效可用。

存储规则的处理方式有何不同

  1. 当您在控制器上调用 .validate() 时,它将首先查找通过 .addObject() 存储的 "local" 规则,然后通过 .validateObject() 将这些规则传递给验证器。

这就是你的情况。规则一次性处理,序列表现正常。

以下内容在技术上与您的问题无关,但我将其记录在此处以供参考。

  1. 然后它通过注册的绑定(由绑定行为添加)并且对于每个个体 属性 它会在验证器 上调用 .validateProperty() 如果对象没有被存储在控制器上.

所以这一步不会发生在你的情况下,但它会发生在我的 "solution 2" 上。序列不是在对象上 运行 一次,而是每个个体 运行 一次 属性,在某种程度上有效地绕过了序列的行为(它们仍然适用于 属性 级别, 只是不在对象级别)

所以我必须说这是一个有趣的发现:)