Description
Description
When the debug toolbar is enabled each ajax request add two event listeners to the document.
It seems that in base_js.html.twig
the method addEventListener
is called within the renderAjaxRequests
method which is called on each ajax call. This bind new event listeners on each ajax request to the document.
Not sure if it should be feature request or bug report as this is not critical but I was searching why event listeners where stacking and it took me some time to find it.
name : symfony/web-profiler-bundle
descrip. : Symfony WebProfilerBundle
keywords :
versions : * v5.0.8
web-profiler-bundle/Resources/views/Profiler/base_js.html.twig
var renderAjaxRequests = function() {
(…)
addEventListener(document.querySelector('.sf-toolbar-ajax-clear'), 'click', function() {
requestStack = [];
renderAjaxRequests();
successStreak = 4;
document.querySelector('.sf-toolbar-ajax-request-list').innerHTML = '';
});
}
Suggestion
I have not fully understood how the toolbar javascript works but moving the addEventListener
call on the loadToolbar
method after the intial renderAjaxRequests
should do the trick. The renderAjaxRequests
does not create / remove any html but only work with classes and internal attributes so it seems it should be ok.
Moving it under the loadToolbar
removes the event listeners stacking and the ajax call toolbar seems to be ok but I did not test this thoroughly and only with Chrome.
loadToolbar: function(token, newToken) {
newToken = (newToken || token);
this.load(
(…)
renderAjaxRequests();
addEventListener(document.querySelector('.sf-toolbar-ajax-clear'), 'click', function() {
requestStack = [];
renderAjaxRequests();
successStreak = 4;
document.querySelector('.sf-toolbar-ajax-request-list').innerHTML = '';
});
)
}
Example
Here is the code used to monitor event listeners :
event-tracker.js
window.eventListenerList = [];
Element.prototype.originalAddEventListener = Element.prototype.addEventListener;
Element.prototype.addEventListener = function (type, listener, capture) {
this.eventListenerList = this.eventListenerList || [];
this.eventListenerList[type] = this.eventListenerList[type] || [];
capture = capture || false;
this.originalAddEventListener(type, listener, capture);
const event = {
listener: listener,
useCapture: capture,
};
this.eventListenerList[type].push(event);
window.eventListenerList.push(event);
};
Element.prototype.getEventListeners = function () {
this.eventListenerList = this.eventListenerList || {};
return this.eventListenerList;
};
Element.prototype.originalRemoveEventListener = Element.prototype.removeEventListener;
Element.prototype.removeEventListener = function (type, listener, capture) {
capture = capture || false;
this.originalRemoveEventListener(type, listener, capture);
const event = {
listener: listener,
useCapture: capture,
};
this.eventListenerList[type] = this.eventListenerList.filter(e => e !== event);
window.eventListenerList = window.eventListenerList.filter(e => e !== event);
};
On any template using twig with profiler enabled with only the above javascript added :
(input) = type in console and validate
Chrome console
// List page initial event listeners
(input) window.eventListenerList
(5) [{…}, {…}, {…}, {…}, {…}]
// Do an ajax request and display event listeners again
(input) fetch('https://google.com');
(input) window.eventListenerList
(7) [{…}, {…}, {…}, {…}, {…}, {…}, {…}]
// New event listeners informations
(input) window.eventListenerList[6].listener
ƒ () { requestStack = []; renderAjaxRequests(); successStreak = 4; document.querySelector('.sf-toolbar-ajax-request-list').innerHTML = ''; …
(input) window.eventListenerList[5].listener
ƒ () { requestStack = []; renderAjaxRequests(); successStreak = 4; document.querySelector('.sf-toolbar-ajax-request-list').innerHTML = '';