Re-submitting multiplied Form rendered in <tr> redrawed by snippet ajax
- jirkov
- Member | 3
Hi. I am using Naja.js to handle ajax. Here are 3 same forms multiplied by Multiplier rendered in table>tr in 3 different ways. Form is submitted by Naja ajax and redrawed correctly after first submission. But only first 2 ‘mysnippet’ and ‘mysnippet2’ can be submitted again after snippets redraw.
{snippet mysnippet}
<table>
<tr n:foreach="$items as $item">
<td>
{control form2-$item}
</td>
</tr>
</table>
{/snippet}
{snippet mysnippet2}
<table>
<tr n:foreach="$items as $item">
<td>
{form form2-$item}
{input submit}
{/form}
</td>
</tr>
</table>
{/snippet}
{snippet mysnippet3}
<table class="formTable">
<tbody>
<tr n:foreach="$items as $item">
{form form2-$item}
<td>
<input n:name=submit>
</td>
{/form}
</tr>
</tbody>
</table>
{/snippet}
What is different in these 3 ways of rendring is that in mysnippet3 the inputs are rendered outside <form></form> tag but this is OK in terms of valid HTML. I am not sure whether it is Naja or Form/Latte issue or I do miss something.
How do you solve forms on table>rows repeatedly submitted by ajax? Thank
you in advance.
I searched for the solution few times, this is not firs time I try to
solve this
- m.brecher
- Generous Backer | 872
Hi @jirkov
But only first 2 ‘mysnippet’ and ‘mysnippet2’ can be submitted again after snippets redraw.
This means that forms in the first group after first submit redraw correctly but next submitting works not ?? Here we need to inspect whats wrong – look the rendered html of the forms, the problems might be in slight different html after redraw. You unfortunately didnt posted other important code – the forms and presenter. May be something is wrong there ??
If you compare working and not working variants – works not variant with {control}, where form is rendered as component. Do you use for this form a latte template ? And what code is insight ?
- jirkov
- Member | 3
Hi @m.brecher
Just for simplification I removed mysnippet as the form is rendered by {control …} in there and it simply works.
In mysnippet2 and mysnippet3 I use {form …} to render the form. Problem is that the form in mysnippet3 is not submited after first submission (after ajax snippets redraw).
I have checked HTML code in <div id=“snippet–mysnippet3”> after snippet redraw and it is absolutely the same as the original one after first page full load (F5). Only time in submit values changes – this I use to recognize form redraw.
In presenter there is:
public function startup(): void
{
parent::startup();
$this->items = [1,2];
}
public function renderDefault(): void
{
$this->template->items = $this->items;
}
public function createComponentForm2(): Multiplier
{
return new Multiplier(function($id) {
$form = $this->formFactory->create(ajax:true);
$time = DateTime::from("now")->format("H:i:s");
$form->addSubmit('submit', 'ok '.$time);
$form->onSuccess[] = [$this, 'Form2Succeeded'];
return $form;
});
}
public function Form2Succeeded($form, $vals): void
{
if($this->isAjax()){
$this->redrawControl();
}else{
$this->redirect('this');
}
}
Resulting HTML is here.
<div>
<div id="snippet--mysnippet2">
<table>
<tbody>
<tr>
<td>
<form action="/vypis/fix/" method="post" class=" ajax" id="frm-form2-1">
<input type="submit" name="_submit" value="ok 11:02:19">
<input type="hidden" name="_do" value="form2-1-submit">
<!--[if IE]><input type=IEbug disabled style="display:none"><![endif]-->
</form>
</td>
</tr>
<tr>
<td>
<form action="/vypis/fix/" method="post" class=" ajax" id="frm-form2-2">
<input type="submit" name="_submit" value="ok 11:02:19">
<input type="hidden" name="_do" value="form2-2-submit">
<!--[if IE]><input type=IEbug disabled style="display:none"><![endif]-->
</form>
</td>
</tr>
</tbody>
</table>
</div>
<hr>
<div id="snippet--mysnippet3">
<table>
<tbody>
<tr>
<form action="/vypis/fix/" method="post" class=" ajax" id="frm-form2-1"></form>
<td>
<input type="submit" name="_submit" value="ok 11:02:19">
</td>
<input type="hidden" name="_do" value="form2-1-submit">
<!--[if IE]><input type=IEbug disabled style="display:none"><![endif]-->
</tr>
<tr>
<form action="/vypis/fix/" method="post" class=" ajax" id="frm-form2-2"></form>
<td>
<input type="submit" name="_submit" value="ok 11:02:19">
</td>
<input type="hidden" name="_do" value="form2-2-submit">
<!--[if IE]><input type=IEbug disabled style="display:none"><![endif]-->
</tr>
</tbody>
</table>
</div>
</div>
- nightfish
- Member | 518
@jirkov
Your HTML in mysnippet3 is not valid. As per specification
<tr>
cannot contain <form>
as its
immediate child.
It can be seen on the resulting HTML you posted:
jirkov wrote:
Resulting HTML is here.<div id="snippet--mysnippet3"> <table> <tbody> <tr> <form action="/vypis/fix/" method="post" class=" ajax" id="frm-form2-1"></form> <td> <input type="submit" name="_submit" value="ok 11:02:19"> </td> <input type="hidden" name="_do" value="form2-1-submit"> <!--[if IE]><input type=IEbug disabled style="display:none"><![endif]--> </tr>
You see that <form>
is immediatelly closed by
</form>
and your submit button is therefore outside of the
form. That would probably be enough to prevent form from submitting.
Fix your HTML structure and the problem will resolve itself.
- m.brecher
- Generous Backer | 872
@jirkov
I have checked HTML code in <div id=“snippet–mysnippet3”> after snippet redraw and it is absolutely the same as the original one after first page full load (F5).
As @nightfish commented above – html code in mysnippet3 is invalid – fix this will solve all problems. What is however interesting that html is identical before and after first submit and first submit works, second not.
It depends what html structure you inspect – static in source code of the page or real one in browser DOM. In case that html is invalid the browser might create element nodes in browser DOM in a different way than you expect. Inspect the html code of 3. form in DOM with Chrome DevTools and inspect the real structure of the 3. form before and after submitting.
- jirkov
- Member | 3
Finally I have a working solution (googled for “form in tr”). Adding form="" attribute with form id as their value to all form inputs match those inputs to the form. Naja.js then submits form correctly after snippets redraw with inputs still outside form tag.
{snippet mysnippet3}
<table>
<tbody>
<tr n:foreach="$items as $item">
{form form2-$item}
<td>
<input n:name=submit form="frm-form2-{$item}">
<input n:name=_do form="frm-form2-{$item}">
</td>
{/form}
</tr>
</tbody>
</table>
{/snippet}
It is necessary to add form="" attribute also to hidden input with
name=“_do”
Does anybody know how to do that in php when creating
that form?
Thank you guys @nightfish @m.brecher you were right – form inside or outside tr is not valid. That is why browser modifies DOM so that <form></form> is before the first td and inputs are outside form. But this happens in both cases first full page load and snippet redraw. I have checked final HTML in browser dev tools and HTMLs were the same. Still submission after ajax snippet redraw did not work.
I knew (just feeling) that tr>form>td>input is not super correct but Latte allowes it and those forms worked correctly and I used it very often. But when I started “ajaxify” large tables with meny rows with form on each I struggled with 2nd ajax submit all the time. That was why I originally asked How do you solve forms on table>rows repeatedly submitted by ajax?
To me form=“{$formid}” on all the inputs is the solution.
- David Grudl
- Nette Core | 8228
I've considered in the past that if <form>
has an
id
attribute, it could automatically add a form
attribute with that value to all elements. That would solve the _do
issue as well.
- mskocik
- Member | 62
David Grudl wrote:
I've considered in the past that if
<form>
has anid
attribute, it could automatically add aform
attribute with that value to all elements. That would solve the_do
issue as well.
This would be really nice, maybe just enable-able feature. Because form has
id
attribute always set if I am not mistaken.