Browse Source

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

Claude Paroz 3 years ago
parent
commit
eabc22f919

+ 3 - 5
django/contrib/admin/static/admin/js/autocomplete.js

@@ -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();
+    });
 }

+ 11 - 2
django/contrib/admin/static/admin/js/inlines.js

@@ -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);

+ 15 - 44
docs/ref/contrib/admin/javascript.txt

@@ -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
-    });

+ 4 - 0
docs/releases/4.1.txt

@@ -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

+ 9 - 15
js_tests/admin/inlines.test.js

@@ -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) {