Support for Drupal 7 is ending on 5 January 2025—it’s time to migrate to Drupal 10! Learn about the many benefits of Drupal 10 and find migration tools in our resource center.
This behaviour was tricky to lock down but the following are steps to reproduce the issue:
1. Create a field instance of tablefield with Unlimited cardinality, with default rows/columns to 5/5
2. Create a node of this type
3. In the first table entry, change the rows/cols to 1/1, put some text in the only cell
4. In the second entry, change the rows/cols to 1/1, put some text in the only cell
5. Save the node
You end up with the first table defaulting back to 5/5 and the second table being written correctly.
I'm going to poke the source now to try to find the reason.
Comment | File | Size | Author |
---|---|---|---|
#17 | tablefield-allow_multiple_table_updates_via_ajax-2052215-17.patch | 2.5 KB | vitalie |
#12 | tablefield-allow_multiple_table_updates_via_ajax-2052215-12.patch | 1006 bytes | rjacobs |
Comments
Comment #1
er_d0s CreditAttribution: er_d0s commentedOK so it seems like if you modify a number of row/column settings at once, only the last modified table will be correctly updated.
I THINK the problem lies somewhere around the start of the tablefield_field_widget_form function. Something to do with how the function deals with default values. Note that if a new node has 3 tablefield values in the form, when you click resize tablefield_field_widget_form will be called 3 times.
Comment #2
er_d0s CreditAttribution: er_d0s commentedI'm raising this to critical because in some cases it renders the module unusable, I'll try to work on the problem as soon as I can but if anyone can get to it before me that would be great.
Comment #3
er_d0s CreditAttribution: er_d0s commentedComment #4
rjacobs CreditAttribution: rjacobs commentedExactly! This is the same issue that we are encountering as well. I posted some notes about it at #1361702: Rebuild or csv upload action that shrinks table size not being honored (old roes/columns persist after save) which I am going to mark as a dup of this issue (as this one seems more recent/active).
I was poking around in the code a bit as well (tablefield_rebuild_form_ajax(), etc.) but did not see an obvious solution. I would like to explore this more but won't personally be able to dedicate time to it until some deadlines pass. We have some workarounds in place that allow us to avoid this issue for now, but I know its going to come back to bite us later. I may jump-back in on this at some point, but will certainly help review any patches that may be posted.
Comment #5
rjacobs CreditAttribution: rjacobs commentedAlso I don't think the "needs work" status should be used until after there is a patch available for review (as it signifies that an existing patch was reviewed but needs more work before it can be reviewed further).
Comment #6
er_d0s CreditAttribution: er_d0s commentedHey thanks for popping in! This bug has been killing me and I've only been able to devote a few hours here and there but I'm going to have to address it within the next few weeks as I've got a project that's relying on it, hopefully I'll have a patch soon.
Comment #7
Kevin Hankens CreditAttribution: Kevin Hankens commentedThanks for keeping this alive :) A patch for this would be most welcome!
Comment #8
er_d0s CreditAttribution: er_d0s commentedOK! I think I've fixed it, the problem seemed to be that tablefield_rationalize_table() was being called with the default value for the form in the case of the first tablefield in the list. The issue was at line 409, I can see that the start of that function (tablefield_field_widget_form) there's some initial processing to decide what to do with the form in different contexts, line 409 seems to be doing some initial setting up, but I couldn't find a use case where the block was executed without breaking the form. Rather than delete it I just added an extra check to make sure we're in the right context.
Kevin, can you confirm what that block was for?
Comment #9
rjacobs CreditAttribution: rjacobs commentedThanks erdos, I hope to give this a test shortly. Marking "needs review" as there is now a patch for review.
Comment #10
er_d0s CreditAttribution: er_d0s commentedComment #11
rjacobs CreditAttribution: rjacobs commentedOh man, sorry that it's taken so long to review this as promised. I got hung up on a number of deadlines.
Unfortunately, I didn't have luck with the patch in #8. Even with it applied I was still unable to get more than one re-sized/imported table to save correctly. As before only the last edited table was saved correctly.
No matter what, your analysis helps contextualize the issue, and I agree that something funky is going on in tablefield_field_widget_form() (most likely related to the initial calculation of the $default_value variable). After staring at the code a bit it seems like the default data for each tablefield is being reset (fetched freshly out of the DB) on each ajax submit except for the element that is triggering the ajax submit. Based on my understanding of the FAPI this makes sense, as I believe the entire form must be re-built (calling each fields' hook_field_widget_form()) even if only one form element will be changed via ajax. When this happens, it seems that tablefield_field_widget_form() isn't smart about maintaining the default values from the form_state of any tablefields that are not being updated via the ajax request, and instead it (re)loads their data from the DB. This is of course a problem if they happened to have been updated on a previous ajax request. This "resetting" is not reflected in the browser as the ajax only updates the triggering field visually, but it does affect the default values in the form_state data, which is ultimately what's saved.
So it seems to me that we need to bypass the part of tablefield_field_widget_form() that re-loads fresh data from the DB when a tablefield is being re-built via ajax but is not the field that triggered the ajax. I think that is here (around line 411):
Changing this to something like the following might ensure that these tablefields are always rebuilt from form_state data (in the final
else { }
) as opposed to being refreshed from the DB:I'll look at this some more and if it's working I'll make a patch.
Comment #12
rjacobs CreditAttribution: rjacobs commentedOk, I've played around a bit more with the change noted from my previous comment and have been seeing good results. With this change we have been able to successfully do several complex sets of edits that were not possible before (import via CSV to overwrite existing data, re-size multiple tables, mix/match imports and re-sizes on same save, etc.). So I'm rolling as a path (made with git format-patch). It's a very simple patch.
erdos, Kevin, would you be able to check this out?
Comment #13
rjacobs CreditAttribution: rjacobs commentedJust wanted to bump this. Anyway else able to test this (very simple) patch so we can try to get a fix committed?
Comment #15
vitalie CreditAttribution: vitalie commentedThx @rjacobs. I have also played around and it looks good. There is still a problem if one sets some default values in field settings and locks them. I think this is because those values do not end up in $form_state['input'].
Comment #16
vitalie CreditAttribution: vitalie commentedComment #17
vitalie CreditAttribution: vitalie commentedHere's a patch based on #12 that deals with locked values.
Comment #19
vitalie CreditAttribution: vitalie commentedComment #20
vitalie CreditAttribution: vitalie commentedThis still does not work in the new node creation form, although it does work in the node edit form. Debugging shows that in the case of node creation the following if clause gets triggered:
in tablefield_widget_form function.
One should probably add to it the && !isset($form_state['clicked_button']['#value']) check as in the patch above.
Comment #21
uno CreditAttribution: uno commentedSame problem when having more than one tablefield field.
Comment #22
vitalie CreditAttribution: vitalie commented@uno, it might be that the problem you report got fixed by the fix of #2387001: Import CSV option does not work with Field Collection module. Could you check?
Comment #23
uno CreditAttribution: uno commentedHi vitalie,
Thanks for reply, could you point me to the fix?
Comment #24
vitalie CreditAttribution: vitalie commentedSorry, @uno, I suspect it is this one: https://www.drupal.org/node/2387001#comment-9574877, I am not sure the patch there will apply cleanly to the 7.x-2.3 version, could you test it on current dev version?
Comment #25
vitalie CreditAttribution: vitalie commentedRe #20, the patch has been committed as part of #1673416: Image upload interferes with Rebuild table
Comment #26
vitalie CreditAttribution: vitalie commented