Closed mvlach closed 8 years ago
Hi @mvlach,
Why the refinement method is not called
maybe structs are not (yet) supported:
var Person = t.struct({
name: t.Str,
surname: t.Str,
email: Email,
passwords: t.maybe(Type) // <= not supported
});
can you please create one advanced validation example
First version (without point 2.):
var Email = t.refinement(t.String, function (s) {
return /@/.test(s);
});
var Password = t.refinement(t.String, function (s) {
return s.length >= 2;
});
function samePasswords(x) {
return x.newPassword === x.confirmPassword;
}
var Type = t.subtype(t.struct({
name: t.String,
surname: t.String,
email: Email,
newPassword: Password,
confirmPassword: Password
}), samePasswords);
var options = {
error: 'Passwords must match',
fields: {
email: {
error: 'Invalid email'
},
newPassword: {
type: 'password',
error: 'Invalid password, enter at least 2 chars'
},
confirmPassword: {
type: 'password',
error: 'Invalid password, enter at least 2 chars'
}
}
};
var App = React.createClass({
onSubmit(evt) {
evt.preventDefault();
var value = this.refs.form.getValue();
if (value) {
console.log(value);
}
},
render() {
return (
<form onSubmit={this.onSubmit}>
<t.form.Form
ref="form"
type={Type}
options={options}
/>
<div className="form-group">
<button type="submit" className="btn btn-primary">Save</button>
</div>
</form>
);
}
});
Second version (with point 2.):
var Email = t.refinement(t.String, function (s) {
return /@/.test(s);
});
var Password = t.refinement(t.String, function (s) {
return s.length >= 2;
});
function samePasswords(x) {
return x.newPassword === x.confirmPassword;
}
var Type = t.subtype(t.struct({
name: t.String,
surname: t.String,
email: Email,
newPassword: Password,
confirmPassword: Password
}), samePasswords);
var defaultOptions = {
fields: {
email: {
error: 'Invalid email'
},
newPassword: {
type: 'password',
error: 'Invalid password, enter at least 2 chars'
},
confirmPassword: {
type: 'password',
error: 'Invalid password, enter at least 2 chars'
}
}
};
var App = React.createClass({
getInitialState() {
return {
value: {},
options: defaultOptions
};
},
onSubmit(evt) {
evt.preventDefault();
this.setState({options: defaultOptions});
var value = this.refs.form.getValue();
if (value) {
console.log(value);
}
else {
if (this.state.value.confirmPassword && !samePasswords(this.state.value)) {
this.setState({options: t.update(this.state.options, {
fields: {
confirmPassword: {
hasError: { $set: true },
error: { $set: 'Password must match' }
}
}
})});
}
}
},
onChange(value) {
this.setState({value});
},
render() {
return (
<form onSubmit={this.onSubmit}>
<t.form.Form
ref="form"
type={Type}
options={this.state.options}
value={this.state.value}
onChange={this.onChange}
/>
<div className="form-group">
<button type="submit" className="btn btn-primary">Save</button>
</div>
</form>
);
}
});
@gcanti thanks you for the fast answer. I'll try this solutions.
The seconds does what I need but I think that this validation should be at the domain...
Have a nice day...
M.
The seconds does what I need but I think that this validation should be at the domain...
Maybe that's a matter of some philosophical debate: we are talking about error messages here and in my opinion they belongs to the layout / display world (hence they go in the option
prop).
The domain models:
var Email = t.refinement(t.String, function (s) {
return /@/.test(s);
});
var Password = t.refinement(t.String, function (s) {
return s.length >= 2;
});
function samePasswords(x) {
return x.newPassword === x.confirmPassword;
}
var Type = t.subtype(t.struct({
name: t.String,
surname: t.String,
email: Email,
newPassword: Password,
confirmPassword: Password
}), samePasswords);
already contain the whole information for validation purposes:
var value = {
name: 'Giulio',
surname: 'Canti',
email: 'user@domain.com',
newPassword: 'aaaaaa',
confirmPassword: 'bbbbbb'
};
console.log(t.validate(value, Type).isValid()); // => false
Having said this, if you like to attach the validation messages to your types there's a third option, exploiting the getValidationErrorMessage
(it will be automatically used as error
option):
// again without point 2. for simplicity
t.String.getValidationErrorMessage = function () {
return 'Required field';
};
var Email = t.refinement(t.String, function (s) {
return /@/.test(s);
});
Email.getValidationErrorMessage = function () {
return 'Invalid email';
};
var Password = t.refinement(t.String, function (s) {
return s.length >= 2;
});
Password.getValidationErrorMessage = function () {
return 'Invalid password, enter at least 2 chars';
};
function samePasswords(x) {
return x.newPassword === x.confirmPassword;
}
var Type = t.subtype(t.struct({
name: t.String,
surname: t.String,
email: Email,
newPassword: Password,
confirmPassword: Password
}), samePasswords);
Type.getValidationErrorMessage = function (value) {
if (!samePasswords(value)) {
return 'Password must match';
}
};
var options = {
fields: {
newPassword: {
type: 'password'
},
confirmPassword: {
type: 'password'
}
}
};
var App = React.createClass({
getInitialState() {
return {value: {}};
},
onSubmit(evt) {
evt.preventDefault();
var value = this.refs.form.getValue();
if (value) {
console.log(value);
}
},
onChange(value) {
this.setState({value});
},
render() {
return (
<form onSubmit={this.onSubmit}>
<t.form.Form
ref="form"
type={Type}
options={options}
value={this.state.value}
onChange={this.onChange}
/>
<div className="form-group">
<button type="submit" className="btn btn-primary">Save</button>
</div>
</form>
);
}
});
Hi @gcanti,
I'm trying to do the exact same thing (double password field that must match). Using t.subtype(), the form doesn't show up anymore.
Is t.subtype() still supported? What's the best way to achieve that?
@enguerranws yes is still supported as t.subtype
is an (old) alias of t.refinement
This works for me
const Email = t.refinement(t.String, (s) => {
return /@/.test(s)
})
const Password = t.refinement(t.String, (s) => {
return s.length >= 2
})
function samePasswords(x) {
return x.newPassword === x.confirmPassword
}
const Type = t.refinement(t.struct({
name: t.String,
surname: t.String,
email: Email,
newPassword: Password,
confirmPassword: Password
}), samePasswords)
const defaultOptions = {
fields: {
email: {
error: 'Invalid email'
},
newPassword: {
type: 'password',
error: 'Invalid password, enter at least 2 chars'
},
confirmPassword: {
type: 'password',
error: 'Invalid password, enter at least 2 chars'
}
}
}
class App extends React.Component {
state = {
value: {},
options: defaultOptions
}
onSubmit = (evt) => {
evt.preventDefault()
this.setState({options: defaultOptions})
const value = this.refs.form.getValue()
if (value) {
console.log(value)
} else {
const { newPassword, confirmPassword } = this.state.value
if (newPassword && confirmPassword && !samePasswords(this.state.value)) {
this.setState({options: t.update(this.state.options, {
fields: {
confirmPassword: {
hasError: { $set: true },
error: { $set: 'Password must match' }
}
}
})})
}
}
}
onChange = (value) => {
this.setState({value})
}
render() {
return (
<form onSubmit={this.onSubmit}>
<t.form.Form
ref="form"
type={Type}
options={this.state.options}
value={this.state.value}
onChange={this.onChange}
/>
<div className="form-group">
<button type="submit" className="btn btn-primary">Save</button>
</div>
</form>
)
}
}
Well, in my case, it just doesn't show the form. No errors given.
My form model looks like:
const formType = t.refinement(t.struct({
email: Email,
password: Password,
password2: Password
}), samePasswords);
Where samePasswords
and Password
the exact same functions as the example above.
However, if I simply do:
const formType = t.struct({
email: Email,
password: Password,
password2: Password
});
It works has expected. But no password matching validation. What do I miss?
Hi, I woud like to validate a struct.
http://jsbin.com/lejijawome/edit?js,console,output
The Passwords are are not evaluated correctly. Why the refinement method is not called ? I tried to set the Passwords as optional, but the label displays "Optional", but it still needs a value.
I would like to use this scenario:
@gcanti: can you please create one advanced validation example ? From real life ?
Let's imagine:
Thanks Mila