Closed mohanzhang closed 8 years ago
Hi @mohanzhang,
Or even if you can think of which commit might have changed this behavior
I guess this one: "de-optimise structs / lists onChange, fix #235" (https://github.com/gcanti/tcomb-form/commit/e674ef2c3120ac6a286f470434533f89136f81e3)
I think you can fix your issue making your custom transformer.format idempotent (as it should be https://github.com/gcanti/tcomb-form/blob/master/GUIDE.md#transformers), this is my quick test:
const Type = t.struct({
amount: t.Number
});
const defaultNumberTransformer = t.form.Textbox.numberTransformer;
const options = {
fields: {
amount: {
transformer: {
format: (n) => (
t.Nil.is(n) || t.String.is(n) ? n : // idempotency!
(n / 100).toFixed(2) // get bucks
),
parse: (s) => {
const n = defaultNumberTransformer.parse(s);
return t.Number.is(n) ? n * 100 : n; // get cents
}
}
}
}
};
const value = {amount: 120};
const 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}
value={value}
/>
<div className="form-group">
<button type="submit" className="btn btn-primary">Save</button>
</div>
</form>
);
}
});
Is it helpful?
@gcanti Thanks Giulio - idempotency was indeed the key. As always, the completeness and helpfulness of your answers never cease to amaze me :) Cheers!
Yeah, but idempotency isn't really the issue here. What you mean is that even if you pass it garbage then it should just return the garbage. You don't garintie anything about the input is what you mean my "idempotent".
I have a problem in which the "parse" function never seems to get called. Here is my transformer:
const tagsTransformer = {
format: (values) => { // server representation -> form values
if(Array.isArray(values)){
let taxonomys = {};
values.map((tag) => {
if (tag.taxonomy in taxonomys)
taxonomys[tag.taxonomy].push(tag.id);
else
taxonomys[tag.taxonomy] = [tag.id];
});
return taxonomys;
}
else {
return values; // it must be idempotent aka ignore junk
}
},
parse: (values) => { // form values -> server representation
// array of IDs
console.log("parse", values);
return Object.keys(values).reduce((p, c) => p.concat(values[c]), []);
}
};
And here is the console log, note that parse
never gets called
when is
parse
supposed to get called?
Actually what I mean by "Idempotence" is... "Idempotence"
So in this case:
type Transformer<A, B> = {
format: (a: A | B) => B,
parse: (b: B) => A
};
where:
format
should not be "garbage", but A | B
format(format(x))
should be === format(x)
(Idempotence)
I recently upgraded from 0.6.3 to 0.6.10 and noticed that the behavior of transformers seems to have changed. It used to be that they applied to the field when I loaded the form (
format
) and retrieved the value of the form (parse
). But now it seems that the transformers are applying every time I type in the text field.The particular use-case I had been relying on the old behavior for was a field where you could enter a dollar amount, and the form would convert it to cents before submitting the value to the backend. So if you entered 100.50, it would parse the field as 10050.
Now what seems to be happening is that as soon as I type anything, the
format
function is called (which divides the backend value by 100 to put it back into dollars - I am aware of floating point errors and yes, this is a terrible design decision, but humor me here :disappointed: ), so if I type "1", it immediately becomes "0.01". It gets even funnier if you keep typing, because the number keeps getting divided by 100 and eventually floating point errors make the number look hilarious.Any idea what's going on here? Or even if you can think of which commit might have changed this behavior, that would be very useful too. Thanks!