Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Click event on Link component does not fire when I expect it to #1939

Open
martinbean opened this issue Aug 1, 2024 · 3 comments
Open

Click event on Link component does not fire when I expect it to #1939

martinbean opened this issue Aug 1, 2024 · 3 comments

Comments

@martinbean
Copy link

martinbean commented Aug 1, 2024

Versions:

  • @inertiajs/core version: 1.2.0
  • @inertiajs/vue3 version: 1.2.0

Describe the problem:

The click event on a <Link> component does not fire when I expect it to. It seems to fire after before and start events. I’d expect the click event to be fired before these, as me clicking the link happens before any HTTP request is initiated (without Inertia being clairvoyant).

I was hoping to be able to use the click event to then stop propagation, i.e. for links where I want to open a modal instead of make a page visit. I was hoping to use the click event because I’m already defining a before callback in my custom component that wraps Inertia’s <Link> component:

<!-- ActionButton.vue -->
<script setup>
const props = defineProps({
  confirmationText: {
    required: false,
    type: String,
  },
  href: {
    required: true,
    type: String,
  },
});

const confirm = () => props.confirmationText ? window.confirm(props.confirmationText) : true;
</script>

<template>
  <Link v-bind:href="href" v-on:before="confirm">
    <slot></slot>
  </Link>
</template>

I was hoping, from a parent component, I could add a click handler that prevents the event:

<ActionButton v-on:click.prevent="openModal">Open modal</ActionModal>

But this is not possible given how late the click event is called by Inertia. It’s also fired after the start event, and the Inertia docs says the start event is not cancellable. So it’s just far too late in the lifecycle any way.

Steps to reproduce:

I’ve observed this behaviour by adding a <Link> component to a test app and adding event listeners to all events:

<InertiaLink
    href="#"
    v-on:before="console.log('Before')"
    v-on:start="console.log('Start')"
    v-on:progress="console.log('Progress')"
    v-on:success="console.log('Success')"
    v-on:error="console.log('Error')"
    v-on:cancel="console.log('Cancel')"
    v-on:finish="console.log('Finish')"
    v-on:click="console.log('Click')"
>
    Test link
</InertiaLink>

The following is logged in the console:

Before
Start
Click
Success
Finish
@RobertBoes
Copy link
Contributor

i.e. for links where I want to open a modal instead of make a page visit

In that case, why would you use an Inertia link? Inertia links are intended for Inertia navigations, but you're not performing a navigation. This would also cause different behaviours, since Inertia's link would mimic following the href, updating the browser URL etc.

Not sure if prevent would be the right thing here, as the default is already prevented (an anchor that would perform a page visit). You could try @click.capture, which would use capturing, that travels from parent to child.

@martinbean
Copy link
Author

martinbean commented Aug 1, 2024

In that case, why would you use an Inertia link?

@RobertBoes Because that’s what my custom ActionButton component wraps. I wanted to create a generic “button” component that I can use for links or actions like this, without having to drop conditional logic all over my pages to switch between <Link> components or plain HTML <button> elements.

This would work on a vanilla <a> tag:

<a href="#" v-on:click.prevent="openModal">Open modal</a>

No network request would be initiated. But the same behaviour is not observed on Inertia’s <Link> component.

As mentioned, I’d expect a false-y click callback to prevent any network requests, since the network request happens in response to my click.

@RobertBoes
Copy link
Contributor

Inertia just uses a regular Vue onClick event;

onClick: (event) => {

So the same behaviour shouldn't work in Vue either way, right? Being an anchor that's wrapped by a component, which in turn is also wrapped again. Guess it could only work if the event would also be emitted. What you're showcasing with a simple anchor tag isn't the same as what you're doing, as the click.prevent would directly call event.preventDefault() on the anchor click event.

I see Inertia is doing a check to see if preventDefault is called;

event.defaultPrevented ||

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants