Skip to content

Latest commit

 

History

History
53 lines (41 loc) · 1.83 KB

3_20.md

File metadata and controls

53 lines (41 loc) · 1.83 KB

3.20 One form rendered several times

A listing that renders the same form type once per row ends up with several forms of the same name on one page:

{% for user in users %}
    <tr>
        <td>{{ form(forms[user.id]) }}</td>
    </tr>
{% endfor %}

{{ init_js_validation() }}

Every one of those forms is queued on its own, so init_js_validation() renders one addModel() call per rendered form. In the browser each model takes the first nodes that no earlier model is attached to, in document order, which gives every row its own validator, its own errors and its own submit handler. An error of the third row is shown in the third row only.

The renders have to appear in the page in the order their forms were built, because that is the order the models are attached in.

All the elements of a model id are available for customization:

var rows = SvarohJsFormValidator.getFormInstances('profile');
rows[2].children.name.onValidate = function (errors) {
    // Only the third row
};

SvarohJsFormValidator.forms['profile'] keeps the last initialized render.

A render the application takes out of the document again - a modal that is closed, a row a listing replaces - is dropped from the list the next time the same form is initialized, so a page that reloads its forms does not accumulate instances of nodes that are gone.

Forms of the same name repeat their ids, which is not valid HTML and hides all but the first render from document.getElementById() in your own scripts. If you can name the forms yourself, give each row a name of its own:

// Symfony\Component\Form\FormFactoryInterface $formFactory
$forms[$user->getId()] = $formFactory
    ->createNamed('profile_' . $user->getId(), ProfileType::class, $user)
    ->createView()
;

Each row then has ids of its own, and its model gets an id of its own as well.