// components/TodoForm.js
import React from 'react';
import { observe, streamProps } from 'frint-react';
import Todo from '../models/Todo';
function TodoForm(props) {
const {
title,
updateTitle,
} = props;
return (
<div>
<input
type="text"
value={title}
onChange={e => updateTitle(e.target.value)}
/>
</div>
);
}
export default observe(function () {
const todo = new Todo({
title: 'Hello World',
});
return streamProps()
.set(todo.get$(), t => ({ todo: t }))
.set('updateTitle', title => todo.setTitle(title))
.get$();
})(TodoForm);
Validations
This is the missing layer that we can standardize with a package that works with frint-data:
// models/Todo.js
import { Types, createModel } from 'frint-data';
import { Rules } from 'frint-data-validation';
const Todo = createModel({
schema: {
title: Types.string
},
});
// this is optional
Todo.validationRules = [
// built-in rules for fields
{
rule: Rules.notEmpty,
field: 'title',
message: 'empty message',
name: 'titleIsEmpty', // unique name for extracting error messages (optional)
},
// custom rules - not tied to fields
{
rule: function (model) {
if (model.title.length === 0) {
return false;
}
return true;
},
message: 'You are really empty',
name: 'titleIsEmpty2', // unique name (optional)
},
];
export default Todo;
Now to stream validation errors upon changes:
import { validate$ } from 'frint-data-validation';
import Todo from 'models/Todo';
const todo = new Todo({
title: 'Hi',
});
// validate against default rules set at class level
validate$(todo).subscribe(errors => {
console.log(errors);
// [
// {
// name: 'titleIsEmpty',
// message: 'empty message',
// }
// ]
});
// validate against a different set of rules:
validate$(todo, myRulesHere).subscribe(errors => console.log(errors));
Connect validation rules to Component
import React from 'react';
import { observe } from 'frint-react';
import { validate$ } from 'frint-data-validation';
function TodoForm(props) {
const {
title,
validationErrors,
updateTitle
} = props;
// ...
return <JSX />;
}
export default observe(function () {
const todo = new Todo({
title: 'Hello World',
});
return streamProps()
.set(
todo.get$(),
t => ({ todo: t })
)
.set('updateTitle', title => todo.setTitle(title))
.set(
validate$(todo),
validationErrors => ({ validationErrors })
)
.get$();
})(TodoForm);
Async validation
import { validate$ } from 'frint-data-validation';
import Todo from './models/Todo';
const todo = new Todo({
title: 'Hello world',
});
validate$(todo, [
{
rule: function (model) {
// return Promise or Observable (or only one?)
return fetch(`/todo/exists?title=${todo.title}`)
.then(res => res.json()) // { exists: true }
.then(body => body.exists === false);
},
message: 'Todo of the same title exists in server'
}
])
.subscribe(function (errors) {
console.log(errors);
});
Now that we have
frint-data
(#305), we can start thinking about validation for models.This proposal aims to provide the use cases for form validation involving:
frint-data
frint-react
and, the proposed new package:
frint-data-validation
Model
A model can be created as follows:
Connecting to a Component
Form handling:
Validations
This is the missing layer that we can standardize with a package that works with
frint-data
:Now to stream validation errors upon changes:
Connect validation rules to Component
Async validation