Home › Toolset Professional Support › [Resolved] Post Edit Form Duplicating Body Contents When Validation is Triggered
This is the technical support forum for Toolset - a suite of plugins for developing WordPress sites without writing PHP.
Everyone can read this forum, but only Toolset clients can post in it. Toolset support works 6 days per week, 19 hours per day.
Sun | Mon | Tue | Wed | Thu | Fri | Sat |
---|---|---|---|---|---|---|
- | 9:00 – 12:00 | 9:00 – 12:00 | 9:00 – 12:00 | 9:00 – 12:00 | 9:00 – 12:00 | - |
- | 13:00 – 18:00 | 13:00 – 18:00 | 13:00 – 18:00 | 14:00 – 18:00 | 13:00 – 18:00 | - |
Supporter timezone: America/Jamaica (GMT-05:00)
This topic contains 27 replies, has 3 voices.
Last updated by Nigel 2 years, 6 months ago.
Assisted by: Shane.
Languages: English (English ) Spanish (Español )
Timezone: Europe/London (GMT+00:00)
Hi Dave
Shane asked me to look into this.
I have a copy of your site installed locally, and I can see the problem as originally described (although the only validation test on that form (ID 2203) I can see is whether the token date is greater than the end term date).
You mention that "the same" works elsewhere, the problem is specifically with this form.
Can you point me to where I can see and test a working variant that has the same set up? What do I need to trigger validation failing?
Thanks.
Hi Nigel,
From what you describe I'm guessing you've just taken a fresh copy of the site as form ID 2203 was a rebuild of the original form ID 732. For testing purposes, I went through and modified the validation code one at a time to test each of them in turn and each failure/triggering of the validation error message caused the same result. At present, I had left only the Token End Date field validation running as it was a simple test, which is why you're only seeing the one validation present.
If you edit the Term's Archive (ID 448) and change line 23 of the Loop Item code to from:
[cred_form form="edit-term-rebuild"]
To:
[cred_form form="edit-term"]
This will reinstate the original edit form (ID 732). This form will have the other validations running on it except the Token End Date, which can be restored by editing line 91 of the custom code module "custom_form_validations", where you will be able to see form ID 732 commented and 2203 in its place so swapping these obviously sorts that out.
To answer your question about the variants, again you can spot this in the code mentioned above (apologies for the mess it's in, still pulling things apart and working on all that), but the individual validations are used on the individual Term Content Templates to provide editing abilities as well. So instead of clicking on the Edit button in the table on the archive, click on the term name in the left-most column to load up the individual terms page. From here, the first tab that's loaded will be the Term Info tab, and the three edit buttons there are forms that have identical functionality as the individual bits of the overall edit form. So the top one allows you to edit just the Term Name, the middle one the Term Dates and the bottom one the Token End Date. Each of these uses the same validation code and was built from the main edit form by simply removing the bits not needed from a clone.
Validation will trigger the same way as there are several things that it checks:
Obviously with the individual forms only the relevant ones apply, but all should be functional on the main edit form if you make the changes I outlined at the start.
I think that covers everything but please just ask if I've missed anything or your need further clarity, and thank you so much for looking into this!
Languages: English (English ) Spanish (Español )
Timezone: Europe/London (GMT+00:00)
I don't think the issue is in your code, not your validation code at least, because checking the network requests on the working forms (from the template of a single post) vs the non-working version (from the archive), the JSON request is essentially the same, inasmuch as the markup for the updated form (including error messages) is included in the response, and in the non-working version the form markup appears normal (no duplication).
So the issue appears to arise with how that JSON response is handled, in the problematic version appending rather than replacing the form.
I'll focus my attention on that.
Languages: English (English ) Spanish (Español )
Timezone: Europe/London (GMT+00:00)
An update to say that I wanted to disentangle the problem from the specifics of your site, and so I created a test site where I reproduced a similar set up, with edit forms loading in modals submitting via ajax on an archive with validation code that rejects the submission, but it works fine.
So rather than being a bug in Toolset, it really seems to be some problem in your specific implementation, however elusive.
I moved my test site to a sandbox site so that you can see it working.
Here's the archive page where you can test the issue from the front end: hidden link
You can check the back end using the same credentials you provided to Shane for accessing your own site.
You'll there is a CPT "Things", which has a custom field "choices", for which there is a custom archive that includes an edit form in the output, displayed via a modal using the same markup you use on your site.
As that is a bare-bones implementation that works, you are welcome to add the additional customisations you have on your own site to it to see if something breaks it. (Conversely you might remove things from your site to see if something eliminates the problem.) Bear in mind my previous comment that the issue doesn't arise from what is returned from the server, rather in how that is handled.
We both seem to have run into the same problem with this, in so much as it seems to be very specific yet basically unidentifiable.
I have edit forms working in basically identical ways on other archive pages without issue and I've pulled this apart every way I can think of as detailed in my earlier post. Turning every plugin off has not affected it so it's essentially running basic WordPress and the absolute minimum Toolset plugins to operate, but it doesn't change.
All of the AJAX / JS functionality is being handled under the surface by unmodified means, exactly like a basic installation would, I have changed nothing as AJAX / JS is REALLY not my strong point and I'm at a place where I have no idea what else to do about this. What else can I possibly eliminate from the equation to try and get a reaction from it?
If I can't diagnose it, work around it, or even understand it, this problem is looking like it might be really serious for this project as the whole thing hinges on these basic bits of functionality that you expect to simply work. As you say, it's how the response is being handled, but there's nothing except Toolset's AJAX handler that gets anywhere near the response, so this just isn't making any sense.
Languages: English (English ) Spanish (Español )
Timezone: Europe/London (GMT+00:00)
I've been radically simplifying your site (my copy) this morning to try and isolate the problem, including rebuilding the edit form, removing all traces of custom JS, disabling all other code snippets, changing theme etc.
What I've just done, and which seems to have removed the problem, is edit the custom archive to remove everything except what outputs the edit button, along with its modal code to include the form. So I stripped out the table layout etc., and was left with just this in the output section template:
<div class="button-row"> <button type="button" class="btn btn-secondary" data-toggle="modal" data-target="#editTermModal-[wpv-post-id]">Edit</button> </div> <!-- Edit Term Modal --> <div class="modal fade" id="editTermModal-[wpv-post-id]" tabindex="-1" role="dialog" aria-labelledby="editTermModalLabel-[wpv-post-id]" aria-hidden="true"> <div class="modal-dialog" role="document"> <div class="modal-content"> <div class="modal-header"> <h5 class="modal-title" id="editTermModalLabel-[wpv-post-id]">Edit Term in a modal</h5> <button type="button" class="close" data-dismiss="modal" aria-label="Close"> <span aria-hidden="true">×</span> </button> </div> <div class="modal-body"> [cred_form form="edit-term-rebuild"] </div> </div> </div> </div>
Prior to that there was, as you know, quite a bit of code that included multiple modals with the same form inserted in different modals etc., and it appears that there may be some "leakage" between those. That's where I'd focus my efforts.
In regards to the multiple modals with the same form, that was in there purely for testing to see if there were any discrepancies in the modal implementation compared to another archive where it was working perfectly, and there wasn't. It was still in there as I was messing around with it, but to no avail.
In regards to what you've found, I can't seem to replicate it. I've reduced the Loop Item field just as you've done but the error persists. I've tried removing various parts of the archive as well as this bit, including the JS calls to FooTable, but nothing is having any effect on this duplication error.
So I've gone further. I've pulled every part of the archive out except the barebones of the loop (literally just the loop item template) and the loop item code you've got above. No JS, no pagination, no searching, nothing. That stopped the duplication, so I've been gradually reassembling it and what it appears to be tied to is the presence of the table itself somehow. If I reduce the entire archive down to just this:
Loop:
[wpv-layout-start] [wpv-items-found] <!-- wpv-loop-start --> <table > [wpv-post-body view_template="loop-item-in-terms-archive"] </table> <!-- wpv-loop-end --> [/wpv-items-found] [wpv-no-items-found] <strong>[wpml-string context="wpv-views"]No Terms found[/wpml-string]</strong> [/wpv-no-items-found] [wpv-layout-end]
Loop Item:
<div class="button-row"> <button type="button" class="btn btn-secondary" data-toggle="modal" data-target="#editTermModal-[wpv-post-id]">Edit</button> </div> <!-- Edit Term Modal --> <div class="modal fade" id="editTermModal-[wpv-post-id]" tabindex="-1" role="dialog" aria-labelledby="editTermModalLabel-[wpv-post-id]" aria-hidden="true"> <div class="modal-dialog" role="document"> <div class="modal-content"> <div class="modal-header"> <h5 class="modal-title" id="editTermModalLabel-[wpv-post-id]">Edit Term in a modal</h5> <button type="button" class="close" data-dismiss="modal" aria-label="Close"> <span aria-hidden="true">×</span> </button> </div> <div class="modal-body"> [cred_form form="edit-term-rebuild"] </div> </div> </div> </div>
Then it will still fail. However, if you remove or disable the <table> tag then the error stops. This get's us one tiny step closer, but I don't know where to take this now as every archive uses HTML tables without issue, and even with the JS for FooTable disabled the error is still there, it's only when the table itself is disabled it goes.
I'm at a loss to explain this. If it was FooTable or some of the JS then that would make some kind of sense, but what could the table tag possibly be doing to cause this?
Languages: English (English ) Spanish (Español )
Timezone: Europe/London (GMT+00:00)
OK, thanks for the further details.
On my own test site (not a copy of your site, but a clean test site) I've been able to reproduce the issue arising concretely from using table elements (without the distraction of modals).
I will look into it a little further to see if I can pin-point the exact problem before escalating to the developers.
Languages: English (English ) Spanish (Español )
Timezone: Europe/London (GMT+00:00)
I've managed to track down the source of the problem, but I'm afraid it looks like there won't be a solution.
What happens when you submit a form via ajax which is then rejected because of server-side validation, the server response includes the markup for the whole form, but with additional content such as the error messages, and the markup for the original form is swapped out with the markup for the new form.
That ordinarily works, but doesn't when the form is inside a table element.
The source code in our plugin where this happens uses the jQuery replaceWith function to swap out the form markup.
I suspected there could be a bug in that function, and I confirmed the same problem on a simple codepen demo (no WordPress, no Toolset, just a little HTML and jQuery), only when the form is inside a table.
So I hacked our plugin code to change the line where this happens, to replace the jQuery replaceWith function call with some vanilla JavaScript that achieves the same thing (overwriting the outerHTML attribute of the form element).
I expected to be able to offer you a workaround via this route, but found the same problem occurs. I then checked the same on my simple codepen demo and confirmed there that even with vanilla JavaScript it will not work; there is an intrinsic problem when you have an HTML form element inside an HTML table element.
If I had it working with vanilla JS I would have been able to propose the developers fix it, but given the underlying nature of the problem that is not going to be possible, I'm sorry to say.
To be able to continue down this route you'll need to move from using HTML tables to using markup that omits the table element and simulates a table-like layout with CSS.
Sorry I can't go any futher with this.
Wow, what are the odds I'd run into some bizzare and undocumented JS bug! That's just insane.
Thank you so much for you effort in tracking this down, I'd never have gotten there.
This does leave the question of how best to proceed though. Whilst I have you, could I ask your opinion on a possible solution following the path you've suggested please?
The obvious choice seems to be to rebuild the archives etc using Bootstrap Grids instead of tables. That way I can use their container elements along with row classes etc to simulate the table layout, but the problem that presents is the ability to sort the columns, which is the main reason I didn't use them to start with.
I have found a suite of JS tools called HTML Elements (hidden link) that might provide a solution. They seem to have the functionality available within their Smart Grids component (hidden link), is there any chance you could take a quick glance and let me know if you think it could work to solve this issue? I can't see why it wouldn't be compatible with Toolset, but as I've said, JS is not my strong point.
Or if you have any suggestions for a better implementation of a sortable non-table grid that simulates a table I would massively appreciate your thoughts on this please, as I'm stuck without this functionality.
Many thanks again.
Languages: English (English ) Spanish (Español )
Timezone: Europe/London (GMT+00:00)
I took a quick look at the links you shared, and I'm not sure that can help.
In principle it should be possible to output "tables" using some grid structure (e.g. the Bootstrap grid) and then make it possible to filter or sort the rows based on some column.
The problem with the solution you linked to is that it looks like it works entirely via JavaScript. Not that it simply adds sorting via JavaScript, but that the rendering of the table is by JavaScript and the data itself comes via JavaScript.
Views dynamically generates markup. The table structure can be output as HTML, and the data is part of the same HTML.
You would then add a JavaScript library to provide the sorting and/or filtering functionality, based on the existing markup.
I don't know one off the top of my head, but if you find one then the task becomes enqueuing and then initialising the relevant code.
There are extensions available to make sortable Bootstrap tables, but the problem there is that Bootstrap tables use the table element, and you want to emulate a table via a CSS grid.
That was essentially what I was afraid of with that solution. I spent quite a long time searching around trying to find something and I genuinely can't find an existing solution for sorting the Bootstrap Grid. There are plenty available to drag and drop and reorganise the grid, but nothing to simulate the clickable column header sorting we're talking about here.
The nearest thing I've found is this proof of concept solution someone has made and it does indeed seem to work, but is fairly limited in scope and would require expanding for use with date fields and other custom fields. But at present, it seems to be the closest thing I've found, so again any opinions or insights would be gratefully received:
hidden link
I think it should be possible to implement as a custom JS module in WordPress and enqueue it in the headers just like any other script, and then simply call the relevant functions from the Views / Archives. As it only seems to affect the headers, we could continue to generate the dynamic body from the loop as usual, bypassing the issue from the previous one. But this is simply an idea at this point, I'm not going to have time to mess with it for a little while due to workload. But so far this seems to be all I can find that might help.
Languages: English (English ) Spanish (Español )
Timezone: Europe/London (GMT+00:00)
That links seems to be for an Angular app, not sure that will prove very helpful, though whatever solution you come up with will necessarily be a Javascript (or jQuery) solution.
At this point I'll just have to wish you good luck, we are very much in custom-solutions territory. I hope you are able to find a solution.