Saturday, 14 December 2019

How do I attach to the modal closed event from bootstrap 4 via Jquery in a Vue component?

I have a Vue JS project where I've referenced Bootstrap 4 in the index.html page, as well as Jquery. I also have JQuery included via npm. I know there's so much wrong with that, but I'm not sure what to do about it.

That said, I'm trying to capture/hook/listen to the modal closing event. I've created the modals as components that are only rendered if a certain object exists in the vuex store. I've tried all of the following in both the parent component and the child component that is the modal in question. Nothing I've tried so far seems to work.

Any suggestions will be most welcome.

In the tags of the component:

jq(document).ready(function() {
    jq('#EditContactModal').on('hidden.bs.modal', function() {
        // eslint-disable-next-line no-console
        console.log('MODAL HIDDEN');
        //this.ModalCanceled();
    });
});

jq('#EditContactModal').on('hidden.bs.modal', function() {
    // eslint-disable-next-line no-console
    console.log('MODAL HIDDEN');
    //this.ModalCanceled();
});

One thing I did try that sort of works is:

jq(document).ready(function() {
    jq('body').on('click', '#EditContactModal', function () {
        // this.Close();
        this.newEmployee = null;
        this.$store.dispatch('setSelectedContact', null);
    });
});

However, this last bit has the interesting issue of throwing a "TypeError: Cannot read property 'dispatch' of undefined" error. It's like I can't use any of the vue objects within any of the JQuery code.

**** Edit 1 - solution per Satyam Pathak's comments ****

So Satyam's answer is exactly what I needed. I've implemented this in 2 ways and am going back and forth on which way is better practice. I honestly don't know.

The first add the following to my EditContactModal component:

    created() {
        jq(document).on('hide.bs.modal', () => {
            // eslint-disable-next-line no-console
            // console.log('MODAL HIDDEN');
            this.newEmployee = null;
            this.$store.dispatch('setSelectedContact', null);
        });
    },
    beforeDestroy() {
        //remove listener since it's attached to the document and will remain even after
        //this component is destroyed
        jq(document).off('hide.bs.modal');
    },

For whatever reason, providing the '#EditContactModal' selector doesn't work. The event is never attached properly. So, I have to attach the listener to the document. This is done in the Created() event. An interesting side effect is that even though the component is destroyed because the 'setSelectedContact' mutator is called, the listener still exists. That means every time the component is recreated another one is attached. To address this, I added the code in the beforeDestroy() to unattach the listener from the document.

All of this works fine.

Another solution I tried is handling this in the parent component, which happens to be my App.vue component. Here is that code:

    created() {
        jq(document).on('hide.bs.modal', () => {
            this.$store.dispatch('setSelectedContact', null);
            this.$store.dispatch('setSelectedAddress', null);
        });
    }

The application has 2 components that work as modals so that's why there are 2 statements there. This seems the cleaner option of the two.

I do wish I could get the '#EditContactModal' selector working, but I'm guessing this doesn't work due to life cycle issues in how the component is rendered in App.vue. What I mean is this:

<EditContactModal v-if="this.selectedContact"></EditContactModal>

So, when there isn't a "selectedContact" object in the store, there is no EditContactModal div created on the page. For now, I think I'm fine with keeping this in the App.vue, but I'm certainly open to any further thoughts on the subject.

Lastly, I rather do like the suggestion of emitting the modal closed event to the parent. That said, I'd still have to attach to the document for the listener, which also means I'll need to unattach the listener from the component. Given that, and that I have 2 such components that do this, it's simplest to just leave the code in the App.vue component.



from How do I attach to the modal closed event from bootstrap 4 via Jquery in a Vue component?

No comments:

Post a Comment