You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Editing fields in-line/on list is a common functionality present in systems where users' workflows require editing simple textual data at-mass over multiple entities. This RFC aims to bring support of editing fields directly on index lists in EAB:
demo_simple.mp4
In-line edit UX 😃
Ignoring the obvious spreadsheet-driven workflows, there are a myriad of scenarios where in-line edits are prevalent. Examples include:
updating remaining amounts on a list of supplies in a laboratory
inputting test grades for all students who took a test
updating story point value on a list of tasks in a sprint
One of the concrete examples in the app I'm developing is adding common measurements to animals. The physical workflow mandates mass-entry after measurements are taken for multiple animals.
🐌 The current workflow can be seen below:
demo_many_clicks.mp4
🚀 Now, let's try with inline "edits":
demo_not_so_many_clicks.mp4
This is way faster 🎉 It offers a realtime and non-intrusive feedback to the user as well. Naturally, these two ways are not 1:1 comparable, as the full edit contains many more options, but the in-line style can eliminate the majority of "full edits".
Scope 🔍
This feature can get quite complex very quickly. To make it useful I needed to go beyond just simple editing of a text field, as from the beginning my use-case required actually adding a new related entity (as you can probably see on the video).
The planned scope:
a new InlineEditableField which is able to transparently submit a value to the backend
the field should be easy to use and pretty much a drop-in replacement for any scalar type like TextField or NumberField
the field should allow for editing a single scalar entity field
the field should be flexible enough to add new related records
this isn't meant to introduce a full-fledged API, thus it should utilize all fields & forms already present in users' applications. However, it should respond with proper HTTP codes etc.
Implementation 👨💻
What is shown in this RFC isn't a mock-up. It is a working implementation tested in my project. The code isn't PR-ready just yet, however it was written specifically with upstreaming in mind ;) The changes needed aren't extensive.
Data persistence
To support the data persistence changes need to be made to new() and edit() to support POST/PUT/PATCH with application/json payload. While using the standard POST and normal form handling seemed feasible at first, it quickly became a nightmare in our project. There were many reasons like issues with JS FormData not handling arrays, or Symfony Forms not expecting a partial update w/PATCH.
The changes to properly support this part include:
~80 SLOC, reusing Form::submit()
a new protected function getResponseAfterAjaxSave()(draft name) method on AbstractCrudController, which serves a purpose similar to getRedirectResponseAfterSave() and provides a new display value
Field construction
Providing the new field is actually more complicated. The new fields supports the following options:
target controller: configured to the parent entity CRUD by default
target action: Action::EDIT by default, can be changed to Action::NEW
method: can be specified; by default uses PATCH for edit and POST for new
automatically include parent entity ID on edits
allows to include an extra array with additional data; this is indispensable when creating related entities, as there are e.g. required fields
the whole thing is ~200 SLOC
The frontend went through many revisions in my case. Currently, the form for each field is lazy-created as needed by a vanilla JS. The reason for that is provisioning for displaying a list with 5+ editable columns and 100+ rows. That would introduce a severe DOM pollution and a heavy backend load to render something which isn't used 99% of the time (i.e. when browsing lists). Nevertheless, it uses standard Bootstrap popovers & <form> elements. The only custom thing is supporting Esc to abort edit.
The form creation process support setting a size of the field, postfix, name of the "save" button, as well as the optional field placeholder.
Known limitations
the implementation by design supports only scalars (i.e. no selects or other complex things)
validation is delegated to the server
Rationale 👍
I saw this asked in many issues, I was able to quickly locate one: #365. In addition, this feature doesn't set a precedent due to already-present "AJAX".
The only dynamic list field present in EAB is BooleanField, which can be rendered as a "switch". While changing it in any way is out of scope for this issue, it can easily be done. The one-off code in AbstractCrudController::edit() could be removed. The current implementation will certainly be able to handle 1/0 update with just minor JS changes to BooleanField.
Overview (aka. TL;DR)
Editing fields in-line/on list is a common functionality present in systems where users' workflows require editing simple textual data at-mass over multiple entities. This RFC aims to bring support of editing fields directly on
indexlists in EAB:demo_simple.mp4
In-line edit UX 😃
Ignoring the obvious spreadsheet-driven workflows, there are a myriad of scenarios where in-line edits are prevalent. Examples include:
One of the concrete examples in the app I'm developing is adding common measurements to animals. The physical workflow mandates mass-entry after measurements are taken for multiple animals.
🐌 The current workflow can be seen below:
demo_many_clicks.mp4
🚀 Now, let's try with inline "edits":
demo_not_so_many_clicks.mp4
This is way faster 🎉 It offers a realtime and non-intrusive feedback to the user as well. Naturally, these two ways are not 1:1 comparable, as the full edit contains many more options, but the in-line style can eliminate the majority of "full edits".
Scope 🔍
This feature can get quite complex very quickly. To make it useful I needed to go beyond just simple editing of a text field, as from the beginning my use-case required actually adding a new related entity (as you can probably see on the video).
The planned scope:
InlineEditableFieldwhich is able to transparently submit a value to the backendTextFieldorNumberFieldImplementation 👨💻
What is shown in this RFC isn't a mock-up. It is a working implementation tested in my project. The code isn't PR-ready just yet, however it was written specifically with upstreaming in mind ;) The changes needed aren't extensive.
Data persistence
To support the data persistence changes need to be made to
new()andedit()to supportPOST/PUT/PATCHwithapplication/jsonpayload. While using the standardPOSTand normal form handling seemed feasible at first, it quickly became a nightmare in our project. There were many reasons like issues with JSFormDatanot handling arrays, or Symfony Forms not expecting a partial update w/PATCH.The changes to properly support this part include:
Form::submit()protected function getResponseAfterAjaxSave()(draft name) method onAbstractCrudController, which serves a purpose similar togetRedirectResponseAfterSave()and provides a new display valueField construction
Providing the new field is actually more complicated. The new fields supports the following options:
Action::EDITby default, can be changed toAction::NEWPATCHfor edit andPOSTfor newThe frontend went through many revisions in my case. Currently, the form for each field is lazy-created as needed by a vanilla JS. The reason for that is provisioning for displaying a list with 5+ editable columns and 100+ rows. That would introduce a severe DOM pollution and a heavy backend load to render something which isn't used 99% of the time (i.e. when browsing lists). Nevertheless, it uses standard Bootstrap popovers &
<form>elements. The only custom thing is supportingEscto abort edit.The form creation process support setting a size of the field, postfix, name of the "save" button, as well as the optional field placeholder.
Known limitations
Rationale 👍
I saw this asked in many issues, I was able to quickly locate one: #365. In addition, this feature doesn't set a precedent due to already-present "AJAX".
The only dynamic list field present in EAB is
BooleanField, which can be rendered as a "switch". While changing it in any way is out of scope for this issue, it can easily be done. The one-off code inAbstractCrudController::edit()could be removed. The current implementation will certainly be able to handle1/0update with just minor JS changes toBooleanField.WDYT?