Yanick Rochon Yanick Rochon - 3 months ago 14
React JSX Question

How to use node-simple-schema reactively?

Given that there is not much examples about this, I am following the docs as best as I can, but the validation is not reactive.

I declare a schema :

import { Tracker } from 'meteor/tracker';
import SimpleSchema from 'simpl-schema';

export const modelSchema = new SimpleSchema({
foo: {
type: String,
custom() {
setTimeout(() => {
this.addValidationErrors([{ name: 'foo', type: 'notUnique' }]);
}, 100); // simulate async
return false;
}
}
}, {
tracker: Tracker
});


then I use this schema in my component :

export default class InventoryItemForm extends TrackerReact(Component) {

constructor(props) {
super(props);

this.validation = modelSchema.newContext();
this.state = {
isValid: this.validation.isValid()
};
}

...

render() {
...
const errors = this.validation._validationErrors;

return (
...
)
}
}


So, whenever I try to validate
foo
, the asynchronous' custom function is called, and the proper
addValidationErrors
function is called, but the component is never re-rendered when
this.validation.isValid()
is supposed to be false.

What am I missing?

Answer

There are actually two errors in your code. Firstly this.addValidationErrors cannot be used asynchronously inside custom validation, as it does not refer to the correct validation context. Secondly, TrackerReact only registers reactive data sources (such as .isValid) inside the render function, so it's not sufficient to only access _validationErrors in it. Thus to get it working you need to use a named validation context, and call isValid in the render function (or some other function called by it) like this:

in the validation

custom() {
  setTimeout(() => {
    modelSchema.namedContext().addValidationErrors([
      { name: 'foo', type: 'notUnique' }
    ]);
  }, 100);
}

the component

export default class InventoryItemForm extends TrackerReact(Component) {
  constructor(props) {
    super(props);

    this.validation = modelSchema.namedContext();
  }

  render() {
    let errors = [];
    if (!this.validation.isValid()) {
      errors = this.validation._validationErrors;
    }

    return (
      ...
    )
  }
}

See more about asynchronous validation here.