Asked By: Anonymous
I am trying to do basic Aurelia validation on an Aurelia component, but am getting an error.
The Typescript is:
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)
}
}
}
}
The html is:
<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>
Running this I get the following error:
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)
If I change the ValidationRules line to:
ValidationRules.ensure('currentPerson.LastName').minLength(3).required().withMessageKey('lastNameReq').on(this);
then I no longer get the error, but the validation does not work either (this.controller.validate() returns valid when I blank out the last name field). This tallies with what LStarky found here: Aurelia Validation not working with object properties. However if I implement his solution I get the above error.
Solution
Answered By: Anonymous
The above view/view model pair was being used as a custom element within a page – it was the detail section of a master detail window. This meant that the currentPerson property was undefined when the page and custom element were first created, so I got an error when creating a validation rule on that property.
Also, because the currentPerson changes each time you change the row in the master list, I found I had to create the validation rule every time this happened.
So the solution was to make currentPerson observable and set up the validation rule in the currentPersonChanged method. The final code was as follows:
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)
}
}
}
}