naja-js/naja

Before event - can not cancel request

ajarha opened this issue · 14 comments

Potrebujem zrušiť ajax request (class="ajax"). Keď zavolám event.preventDefault() v naja before evente request úspešne pokračuje ďalej. Takýto request neobsahuje X-Requested-With: XMLHttpRequest, čiže vráti celú stránku.

export default class TestPreventDefaultExtension {
	constructor(naja) {
		naja.addEventListener('init', () => {
			console.log('naja: init');
		});

		naja.addEventListener('load', () => {
			console.log('naja: load');
		});

		naja.addEventListener('interaction', () => {
			console.log('naja: interaction');
		});

		naja.addEventListener('before', event => {
			console.log('naja: before');
			event.preventDefault();
			// ajax request continue to 'start', 'success' and 'complete' event
			// request - status: 200 type: xhr
		});

		naja.addEventListener('start', () => {
			console.log('naja: start');
		});

		naja.addEventListener('abort', () => {
			console.log('naja: abort');
		});

		naja.addEventListener('success', () => {
			console.log('naja: success');
		});

		naja.addEventListener('error', () => {
			console.log('naja: error');
		});

		naja.addEventListener('complete', () => {
			console.log('naja: complete');
		});
	}
}

Holy 💩, I've lived in a lie 😱

I confirm that this is a bug, caused by my misunderstanding of how XMLHttpRequest.abort() works – or rather doesn't – before the request has been sent. At first glance, it seems to be quite difficult to fix in the current implementation 😟

I've got a rewrite underway that switches to native Fetch API, which will eventually fix this. Until then, it will have to become a "known issue". Thank you for reporting it and please accept my apologies for the inconvenience.

@jiripudil Hi, is there any workaround with current implementation? I've extension which should cancel request when confirm function returns false.

Thank you! 👍

If it's in reaction to a user interaction (click, form submission), you can use the interaction event, preventDefault should work correctly there.

Jax-p commented

I've been looking so long for this solution. Interaction event works fine in solution mentioned above, thank you.

Is there anything where are all events and their behavior described or place which is editable by community? I did not find it in documentation on js.org.

ex.

naja.addEventListener('interaction', (evt) => {
	(evt.element.hasAttribute("data-confirm")
		&& !confirm(evt.element.getAttribute("data-confirm")))
			&& evt.preventDefault();
});

It's hidden here and editable in the docs/ directory in this repo. I should probably move it to a more prominent place :)

I dont understand documentation say BEFORE event is able to stop request by e.preventDefault(). But it does not work.

function LoaderMenuExtension(naja)
{
	naja.addEventListener('interaction', function(e)
	{
		this.element = e.detail.element;
	});

	naja.addEventListener('before', function(e)
	{
		if( this.element.hasClass('stop-ajax') ) e.preventDefault();
		e.preventDefault();
		if( this.element.id == 'categoryCreateFormSubmit' ) this.element.addClass('stop-ajax');
	});

	return this;
}

Good call, the documentation is misleading because it doesn't work reliably, as discussed in this issue. As this is resolved in the upcoming 2.0, I've removed the sentence from the 1.x docs. For the time being, you can preventDefault() right in the interaction event listener to achieve the same behaviour.

I am sorry but it looks the interaction preventDefault does not work as well. I still can see before log.

	naja.addEventListener('interaction', function(e)
	{
		this.element = e.detail.element;

		if( this.element.hasClass('stop-ajax') ) e.preventDefault();
		e.preventDefault();
		if( this.element.id == 'categoryCreateFormSubmit' ) this.element.addClass('stop-ajax');
	});

	naja.addEventListener('before', function(e)
	{
		console.log('before');
		if( this.element.hasClass('stop-ajax') ) e.preventDefault();
		e.preventDefault();
		if( this.element.id == 'categoryCreateFormSubmit' ) this.element.addClass('stop-ajax');
	});

Hang on, which version are you using? The e.detail.element is a 2.0 thing, in which case you need to attach the interaction event listener to naja.uiHandler instead of just naja. Or, in 1.x event details are accessible directly from the event object (i.e. e.element).

(As 2.0 is not out yet, the docs for it are not published and can at the moment only be found on Github.)

In package.json is 1.7.0 . I am on NPM not Bower. So what should I do? And no event.details.element is not accessible directly in element.

In 1.7.0, you have to access event.element directly, not event.detail.element. Anyway, event.preventDefault() should work in interaction event, it's even tested 🤔

If the problem persists, could you please create a minimal code snippet with which I can reproduce the bug and debug it? I've got this simple repository that you can fork and break :)

I made an example repository for you (composer install + npm install) https://github.com/camohub/mynajasandbox
As I did it I found a problem. There was an fatal error: this.element.hasClass('stop-ajax') is not a function. I AM SORRY there was a lot of errors from ublaboo datagrid so I missed this one.

But the event.element is not available. Only event.detail.element

So the bug is not-a-bug and preventDefault works in interaction listener?

About event.detail - it seems that 1.7.0 accidentally includes some of the assets built for 2.0. If you use dist/Naja.js (it is minified), that should give you 1.7.0 code and event.element will work.

I'll try and find out what's going on and release a patch version that doesn't include any of the 2.0 artifacts. Thanks for helping me find out :)

I'm closing this as it's resolved in 2.0 which is coming out Very Soon(TM)