Aurelia Validation Gives Error: TypeError: Object.defineProperty called on non-object

Aurelia Validation Gives Error: TypeError: Object.defineProperty called on non-object

我正在尝试对 Aurelia 组件进行基本的 Aurelia 验证,但出现错误。

打字稿是:

import { bindable, inject, NewInstance } from 'aurelia-framework';
import { HttpClient } from 'aurelia-fetch-client';
import { validationMessages, ValidationRules, ValidationController } from 'aurelia-validation';

@inject(HttpClient, NewInstance.of(ValidationController))
export class PersonDetail {
    @bindable currentPerson: Person;
    private httpClient: HttpClient;
    public controller: ValidationController;

    constructor(http: HttpClient, controller: ValidationController) {
        this.httpClient = http;

        this.controller = controller;
        validationMessages['lastNameReq'] = 'You must enter a last name';
        ValidationRules.ensure('LastName').minLength(3).required().withMessageKey('lastNameReq').on(this.currentPerson);

    }

    saveToDb() {
        this.controller.validate()
            .then(v => {
                if (v.valid) {

                    // this.httpClient...(do stuff)
                }
             }
        }
}

html是:

<template bindable="currentPerson">

    <form submit.delegate="saveToDb()">
        <p>First Name: <input type="text" class="form-control" value.bind="currentPerson.FirstName"></p>
        <p>Last Name: <input type="text" class="form-control" value.bind="currentPerson.LastName & validate"></p>
        <p>Middle Name: <input type="text" class="form-control" value.bind="currentPerson.MiddleName"></p>
        <p>Gender: <input type="text" class="form-control" value.bind="currentPerson.Sex"></p>
        <p>DOB: <input type="text" class="form-control" value.bind="person.DOB"></p>
        <p>Mobile Phone: <input type="text" class="form-control" value.bind="currentPerson.MobilePhnNbr"></p>
        <p>Email: <input type="text" class="form-control" value.bind="currentPerson.EmailAddr"></p>

        <button type="submit" class="btn-primary">Save to Database</button>
        <ul if.bind="controller.errors">
            <li repeat.for="error of controller.errors">
                ${error.message}
            </li>
        </ul>
    </form>
</template>

运行 我得到以下错误:

aurelia-logging-console.js:47 ERROR [app-router] TypeError: Object.defineProperty called on non-object at Function.defineProperty () at Function.29.Rules.set (rules.js:14) at FluentEnsure.48.FluentEnsure.on (validation-rules.js:347) at FluentRuleCustomizer.48.FluentRuleCustomizer.on (validation-rules.js:95) at PersonDetail.app/components/people/person-detail.PersonDetail.bind (person-detail.ts:27) at View.bind (aurelia-templating.js:1400) at Controller.bind (aurelia-templating.js:3394) at View.bind (aurelia-templating.js:1406) at Controller.bind (aurelia-templating.js:3394) at Controller.automate (aurelia-templating.js:3339)

如果我将 ValidationRules 行更改为:

ValidationRules.ensure('currentPerson.LastName').minLength(3).required().withMessageKey('lastNameReq').on(this);

然后我不再收到错误,但验证也不起作用(this.controller.validate() returns 在我清空姓氏字段时有效)。这与 LStarky 在这里发现的一致:。但是,如果我实施他的解决方案,则会出现上述错误。

通常您在 bind() 方法中设置您的验证规则,特别是如果您正在验证的对象 - this.currentPerson - 是 @bindable,因为它不会有值在调用构造函数时。

constructor(http: HttpClient, controller: ValidationController) {
    this.httpClient = http;

    this.controller = controller;
    validationMessages['lastNameReq'] = 'You must enter a last name';
}

bind() {
    ValidationRules.ensure('LastName').minLength(3).required().withMessageKey('lastNameReq').on(this.currentPerson);
}

根据您的评论,您似乎没有在 parent/container 加载元素时设置当前人物。有几种解决方法:

  1. 您可以使用 if 绑定,它只会在附加了人物时创建人物自定义元素(详细信息部分)。 (在父级中:<person-detail if.bind="currentPerson"><person-detail>)。 if 在结果为真时 add/remove 将元素实际绑定到 DOM 中,因此只有当 person 对象具有值时才会实例化和绑定视图模型
  2. 你可以观察PersonDetail class里面绑定的person对象,只有当它有一个非空值时才调用验证规则。这有点棘手,因为您应该只设置一次验证规则,但有时这是可行的方法。使用名为 currentPersonChanged(newVal, oldVal) 的函数,它会自动为您调用。

如果这不起作用,请告诉我!

上面的 view/view 模型对被用作页面中的自定义元素 - 它是主细节 window 的细节部分。这意味着当页面和自定义元素首次创建时,currentPerson 属性 是未定义的,所以我在 属性 上创建验证规则时遇到错误。

此外,因为每次更改主列表中的行时 currentPerson 都会更改,我发现每次发生这种情况时我都必须创建验证规则。

因此解决方案是使 currentPerson 可观察并在 currentPersonChanged 方法中设置验证规则。最终代码如下:

import { bindable, inject, NewInstance, observable } from 'aurelia-framework';
import { HttpClient } from 'aurelia-fetch-client';
import { validationMessages, ValidationRules, ValidationController } from 'aurelia-validation';

@inject(HttpClient, NewInstance.of(ValidationController))
export class PersonDetail {
    @bindable @observable currentPerson: Person;
    private httpClient: HttpClient;
    public controller: ValidationController;

    constructor(http: HttpClient, controller: ValidationController) {
        this.httpClient = http;

        this.controller = controller;
        validationMessages['lastNameReq'] = 'You must enter a last name';    
    }

    currentPersonChanged() {
        if (this.currentPerson) {
            ValidationRules.ensure('LastName').minLength(3).required().withMessageKey('lastNameReq').on(this.currentPerson);
        }
    }

    saveToDb() {
        this.controller.validate()
            .then(v => {
                if (v.valid) {

                    // this.httpClient...(do stuff)
                }
             }
        }
}