aurelia / validatejs

Enables expressive validation using decorators and/or a fluent API.
MIT License
22 stars 23 forks source link

Validate complex entities #95

Closed jods4 closed 8 years ago

jods4 commented 8 years ago

This is a spin-off of aurelia/validation#252 to answer @adarshpastakia who asked how to validate a Hotel that has a Map of HotelLanguage.

I haven't actually built the code, but I would use something like this:

// 1. Build a custom validator for validatejs. It validates all values of a Map
import { Validator } from 'aurelia-validatejs';
const validator = new Validator() // ugly... or DI

validate.validators.map = function(value: Map) {
  const hasErrors = map.values().some(v => validator.validateObject(v).length > 0);
  // Unfortunately details are lost, but Aurelia's controller will evaluate and display them on the binding as well.
  // This is only really useful for your `validate()` call when saving.
  return hasErrors ? "has invalid values" : null; 
}

// 2. If you want to make it useable with a decorator
import { base, ValidationRule } from 'aurelia-validatejs';

const mapRule = new ValidationRule('map', true);

export function validateValues(targetOrConfig, key, descriptor) {
  return base(targetOrConfig, key, descriptor, mapRule, true);
}

// 3. Now you should be able to do so:
class Hotel {
  @validateValues
  languages: Map<string, HotelLanguages>;
}

@jdanyow Writing this code has shown me a few things: it is cumbersome to write your own validators. Suggestions:

export function validateValues(target, key) {
  getRules(target)[key] = true;
}
jsobell commented 8 years ago

Can I suggest that we don't spin off this thread just yet? We desperately need to get the core functionality nailed down, and if there is a generic requirement for a feature then we need to incorporate or support that in the core system, so discussing options or solutions outside of that will fragment the process of finding a solution. Just a friendly suggestion...

adarshpastakia commented 8 years ago

@jods4 thanks for the example, will give it try and keep you posted

adarshpastakia commented 8 years ago

@jods4 @jdanyow i managed to add the map validator made a slight change to the code, however i faced a couple of issues

const validator = new Validator();
validate.validators.map = function(map: Map<string, any>) {
  const errors = []
  map.forEach((v, k) => {
    console.log(v, validator.validateObject(v));
    if (validator.validateObject(v).length > 0) errors.push(k);
  });
  // Unfortunately details are lost, but Aurelia's controller will evaluate and display them on the binding as well.
  // This is only really useful for your `validate()` call when saving.
  return errors.length > 0 ? `${errors.join(',')} has invalid values` : null;
}

function mapRule(config) {
  return new ValidationRule('map', config);
}
export function validatemap(targetOrConfig?, key?, descriptor?) {
  return base(targetOrConfig, key, descriptor, mapRule);
}
  <ui-language languages.bind="model.languages & validate" select.trigger="changeLanguage($event)" add.trigger="addLanguage($event)" delete.trigger="removeLanguage($event)">Language</ui-language>
{rule: ValidationRule, message: "Null can't be blank", object: HotelLanguage, propertyName: null}
jods4 commented 8 years ago

it wouldn't validate the map object unless i add & validate to the property

Right... :disappointed: This is a limitation of the current aurelia-validation API. Only properties linked to UI bindings are validated. I think @jdanyow wants to add a .validate(object) API to make sure every property of the object gets validated.

i keep getting this error even if the object was valid, it doesn't seem to pick the property name

Really not sure about this one, sorry. You'll have to debug it to find out where it goes wrong :frowning:

jdanyow commented 8 years ago

closing- we have a new release that supports some or possibly all of this stuff. please open an issue in aurelia-validation for anything that's missing