Can't get field to update/recognize changes in controlled form
See original GitHub issueProblem:
Can’t edit values - they revert to the initial value after every keypress
I’m pulling my hair out on this issue, which should be pretty simple - but I can’t get it to work. Disclaimer: I’m fairly new to react, but am otherwise a capable engineer with over 10 years of experience with many languages/platforms/frameworks, most recently AngularJS.
Stack:
- mobx-react-form v1.19.2
- mobx v3.1.0
- react v15.4.2
Goal: Simple Update Form
I’m using the RFX-Stack as a foundation for my new company’s new site. Our existing code base uses mobx heavily and people like it a lot, and from what I’ve learned, there’s a lot to love…
So, I’m trying to add a simple Details page, with an edit Modal to the boilerplate - which is where I’m meeting the resistance. I’m going to explain the basics and hopefully that points to a quick solution. I’ll fill in details as needed.
I was able to get the field to be editable by setting defaultValue
on the fields instead of value
, but that gets into the whole “uncontrolled” form issue - and doesn’t seem to be the route I want to take.
Code
Trying to keep this as short as possible - here’s the highlights from the code …
Form Def: post.form.js
export default new PostForm({
fields: {
title: {
label: 'Title',
rules: 'required|string|between:5,50',
},
completed: {
label: 'Completed',
value: true,
rules: 'boolean',
},
uuid: {
rules: 'string',
},
},
});
Message Details Container .jsx
render() {
const { ui, post } = this.props.store;
const modal = !(postForm && post) ? null : (
<PostCreateModal
open={ui.postCreateModal.isOpen}
item={post.selected}
form={postForm}
/>
);
return (
<div className="pt5">
<h3>Message Details { this.props.params.messageId }</h3>
<PostDetails item={post.selected} />
{ modal }
</div>
);
}
Post Create Modal jsx
This has become quite a mess at this point - this is the “current” state. initForm
is called from the constructor, and the item
is a mobx observable containing values for {title: 'post title', uuid: '1234-abc...'}
static initForm(form, item) {
if (!_.isEmpty(item) && form) {
debugger; // eslint-disable-line
form.fields.forEach((field) => {
console.assert(form.$(field.key) === field, 'Field and Retrieve Field should be the same'); // eslint-disable-line
field.set('initial', item[field.key]);
// field.set('defaultValue', item);
field.set(item[field.key]);
// field.bind('onChange', this.customOnChange);
console.log(`Setting "${field.key}" to "${item[field.key]}" -> (${field.value})`); // eslint-disable-line
console.assert(item[field.key] === field.value, 'Field Values must match asfter init'); // eslint-disable-line
});
form.observe({
path: 'title',
key: 'value', // can be any field property
call: ({ formDx, field, change }) => { // eslint-disable-line
console.log(`Field changed from "${change.oldValue}" to "${change.newValue}"`); // eslint-disable-line
},
});
}
}
customOnChange = field => (e, val) => {
console.log('Handling Event: %o] %s --> %s', e, field.key, val); // eslint-disable-line
field.set('value', val);
console.assert(field.value === val, 'Field Value must match new val after change'); // eslint-disable-line
};
render() {
console.log('Rendering Post Create Modal'); // eslint-disable-line
const { open, form, item } = this.props;
if (!form) { return <div />; }
return (
<Modal
contentLabel="Create Post Modal"
isOpen={open}
onRequestClose={this.handleCloseModal}
style={styles}
>
<div className="m3">
<h3>{item ? 'Edit' : 'Create'} Post</h3>
<form>
<div className="pb3">
<TextField
hintText="Title"
floatingLabelText={form.$('title').label}
name={form.$('title').name}
value={form.$('title').value}
errorText={form.$('title').error}
onChange={this.customOnChange(form.$('title'))}
/>
</div>
<div className="tc">
<button
type="submit"
className={button}
onClick={form.onSubmit}
>Save</button>
</div>
</form>
</div>
</Modal>
);
}
Console Logging:
When typing “abc” into the end of the title field, I get the following in the console:
Rendering Post Details for item: Object
Setting "title" to "Internal Markets Technician" -> (Internal Markets Technician)
Setting "uuid" to "5b41f0d2-ac46-4a8c-a7df-99b5e9d5eaf1" -> (5b41f0d2-ac46-4a8c-a7df-99b5e9d5eaf1)
Rendering Post Create Modal
Rendering Post Create Modal
Handling Event: [Proxy] title --> Internal Markets Techniciana
Field changed from "Internal Markets Technician" to "Internal Markets Techniciana"
Handling Event: [Proxy] title --> Internal Markets Technicianb
Field changed from "Internal Markets Technician" to "Internal Markets Technicianb"
Handling Event: [Proxy] title --> Internal Markets Technicianc
Field changed from "Internal Markets Technician" to "Internal Markets Technicianc"
… and no visible change. I thought I’d be able to catch an event (hence the “field change from …” logger message), but I don’t see anything changing it back to the initial value.
So … what am I missing? What stupid mistake am I making?
Issue Analytics
- State:
- Created 7 years ago
- Comments:7 (4 by maintainers)
Top GitHub Comments
About developing on RFX, I suggest you to use React classes only for containers. Keep the other components as stateless function, pass the props, and leave the mobx flow happen 😄
Thanks for the quick help! That did the trick. I’m planning on packaging up a PR for the rfx-stack to include a basic example to add more CRUD functionality to the baseline. Seems like having a details view + editing functionality fits well into the boilerplate. I’ll ping you with updates shortly from that repo!