Skip to content

Instantly share code, notes, and snippets.

@spion
Last active December 7, 2016 19:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save spion/bf19f8312ad535090f600f1fd1234693 to your computer and use it in GitHub Desktop.
Save spion/bf19f8312ad535090f600f1fd1234693 to your computer and use it in GitHub Desktop.
type ValidationError = string | boolean | null;
function fNoError<T>(t:T):ValidationError { return null }
class FieldState<TField> {
private validator: (val:TField) => ValidationError = fNoError
@observable focused = false
@observable changed = false
@observable finisedEditing = false;
@computed get value():TField {
return this.obj[this.key];
}
constructor(private obj:any, private key: string) {}
@computed get error() {
return this.validator(this.value) || null;
}
@computed get visibleError(): ValidationError {
return (this.finisedEditing && this.error) || null;
}
}
type FieldStates<TForm> = {[Field in keyof TForm]: FieldState<TForm[Field]>}
class Form<T> {
private $_state: FieldStates<T> = {} as any;
public get $state():FieldStates<T> {
if (!this.$_state) {
let self = this;
Object.keys(this).forEach(key => {
(this.$_state as any)[key] = new FieldState(self, key);
})
}
return this.$_state;
}
public $handlers = {
onChange: (e:React.FormEvent<HTMLInputElement>) => {
let key = e.currentTarget.name
let value = e.currentTarget.value
;(this as any)[key] = value;
var $s = this.$state[key as any];
$s.changed = true;
},
onFocus: (e: React.FocusEvent<HTMLInputElement>) => {
let key = e.currentTarget.name
let value = e.currentTarget.value
var $s = this.$state[key as any];
$s.focused = true;
},
onBlur: (e: React.FocusEvent<HTMLInputElement>) => {
let key = e.currentTarget.name
let value = e.currentTarget.value
var $s = this.$state[key as any]
if ($s.changed ) {
$s.finisedEditing = true;
}
$s.focused = false;
}
}
}
function validate<T>(f:(t:T) => ValidationError) {
return (obj: any, key: string, descriptor?: TypedPropertyDescriptor<T>):void => {
obj.$_state[key].validator = f;
}
}
function required(t: string): ValidationError {
return t.length > 0 || "is required"
}
class Person extends Form<Person> {
@validate(required)
@observable name: string;
@validate(required)
@observable birthday: Date;
}
let p = new Person();
p.name + "-" + p.birthday.toString()
p.$state.name.error
p.$state.birthday.error
p.$state.birthday.visibleError
p.$state.birthday.changed
p.$state.birthday.finisedEditing
let elem = <input type="text" name="name" value={p.name} {...p.$handlers} />
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment