Fixed #33328 -- Transformed formset:added/removed to native JS events.

This commit is contained in:
Claude Paroz 2022-02-23 10:33:07 +01:00 committed by GitHub
parent 1f42a352e0
commit eabc22f919
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 42 additions and 66 deletions

View File

@ -27,9 +27,7 @@
$('.admin-autocomplete').not('[name*=__prefix__]').djangoAdminSelect2();
});
$(document).on('formset:added', (function() {
return function(event, $newFormset) {
return $newFormset.find('.admin-autocomplete').djangoAdminSelect2();
};
})(this));
document.addEventListener('formset:added', (event) => {
$(event.target).find('.admin-autocomplete').djangoAdminSelect2();
});
}

View File

@ -88,7 +88,12 @@
if (options.added) {
options.added(row);
}
$(document).trigger('formset:added', [row, options.prefix]);
row.get(0).dispatchEvent(new CustomEvent("formset:added", {
bubbles: true,
detail: {
formsetName: options.prefix
}
}));
};
/**
@ -130,7 +135,11 @@
if (options.removed) {
options.removed(row);
}
$(document).trigger('formset:removed', [row, options.prefix]);
document.dispatchEvent(new CustomEvent("formset:removed", {
detail: {
formsetName: options.prefix
}
}));
// Update the TOTAL_FORMS form count.
const forms = $("." + options.formCssClass);
$("#id_" + options.prefix + "-TOTAL_FORMS").val(forms.length);

View File

@ -8,15 +8,15 @@ Inline form events
==================
You may want to execute some JavaScript when an inline form is added or removed
in the admin change form. The ``formset:added`` and ``formset:removed`` jQuery
events allow this. The event handler is passed three arguments:
in the admin change form. The ``formset:added`` and ``formset:removed`` events
allow this. ``event.detail.formsetName`` is the formset the row belongs to.
For the ``formset:added`` event, ``event.target`` is the newly added row.
* ``event`` is the ``jQuery`` event.
* ``$row`` is the newly added (or removed) row.
* ``formsetName`` is the formset the row belongs to.
.. versionchanged:: 4.1
The event is fired using the :ref:`django.jQuery namespace
<contrib-admin-jquery>`.
In older versions, the event was a ``jQuery`` event with ``$row`` and
``formsetName`` parameters. It is now a JavaScript ``CustomEvent`` with
parameters set in ``event.detail``.
In your custom ``change_form.html`` template, extend the
``admin_change_form_document_ready`` block and add the event listener code:
@ -34,17 +34,14 @@ In your custom ``change_form.html`` template, extend the
.. code-block:: javascript
:caption: app/static/app/formset_handlers.js
(function($) {
$(document).on('formset:added', function(event, $row, formsetName) {
if (formsetName == 'author_set') {
// Do something
}
});
$(document).on('formset:removed', function(event, $row, formsetName) {
// Row removed
});
})(django.jQuery);
document.addEventListener('formset:added', (event) => {
if (event.detail.formsetName == 'author_set') {
// Do something
}
});
document.addEventListener('formset:removed', (event) => {
// Row removed
});
Two points to keep in mind:
@ -53,29 +50,3 @@ Two points to keep in mind:
* ``{{ block.super }}`` is added because Django's
``admin_change_form_document_ready`` block contains JavaScript code to handle
various operations in the change form and we need that to be rendered too.
Sometimes you'll need to work with ``jQuery`` plugins that are not registered
in the ``django.jQuery`` namespace. To do that, change how the code listens for
events. Instead of wrapping the listener in the ``django.jQuery`` namespace,
listen to the event triggered from there. For example:
.. code-block:: html+django
{% extends 'admin/change_form.html' %}
{% load static %}
{% block admin_change_form_document_ready %}
{{ block.super }}
<script src="{% static 'app/unregistered_handlers.js' %}"></script>
{% endblock %}
.. code-block:: javascript
:caption: app/static/app/unregistered_handlers.js
django.jQuery(document).on('formset:added', function(event, $row, formsetName) {
// Row added
});
django.jQuery(document).on('formset:removed', function(event, $row, formsetName) {
// Row removed
});

View File

@ -412,6 +412,10 @@ Miscellaneous
* The ``type="text/css"`` attribute is no longer included in ``<link>`` tags
for CSS :doc:`form media </topics/forms/media>`.
* ``formset:added`` and ``formset:removed`` JavaScript events are now pure
JavaScript events and don't depend on jQuery. See
:ref:`admin-javascript-inline-form-events` for more details on the change.
.. _deprecated-features-4.1:
Features deprecated in 4.1

View File

@ -38,26 +38,20 @@ QUnit.test('added form has remove button', function(assert) {
});
QUnit.test('add/remove form events', function(assert) {
assert.expect(6);
const $ = django.jQuery;
const $document = $(document);
assert.expect(5);
const addButton = this.table.find('.add-row a');
$document.on('formset:added', function(event, $row, formsetName) {
document.addEventListener('formset:added', (event) => {
assert.ok(true, 'event `formset:added` triggered');
assert.equal(true, $row.is('#first-1'));
assert.equal(formsetName, 'first');
$document.off('formset:added');
});
assert.equal(true, event.target.matches('#first-1'));
assert.equal(event.detail.formsetName, 'first');
}, {once: true});
addButton.click();
const deletedRow = $('#first-1');
const deleteLink = this.table.find('.inline-deletelink');
$document.on('formset:removed', function(event, $row, formsetName) {
document.addEventListener('formset:removed', (event) => {
assert.ok(true, 'event `formset:removed` triggered');
assert.equal(true, $row.is(deletedRow));
assert.equal(formsetName, 'first');
$document.off('formset:removed');
});
deleteLink.trigger($.Event('click', {target: deleteLink}));
assert.equal(event.detail.formsetName, 'first');
}, {once: true});
deleteLink.click();
});
QUnit.test('existing add button', function(assert) {