2

I have a table with multiple rows, each row has a button, on clicking the button, a modal window opens contains form element.

After submitting the form, second window opens for confirmation and first window closes.

Below code is my sample work flow.

My problem is

On Escape key press, works when the first window was opened but not able to close the second window when it was opened.

<template>
    <div>
        <table>
            <tr>
                <td>
                    <button @click="openFormWindow">Open form</button>
                </td>
            </tr>
        </table>
        <modal v-on-escape="hideFirstModal" v-if="isFirstWindowOpen">
            <div>
                <form @submit="submitFormOne">
                    <input type="text">
                    <button type="submit"></button>
                </form>
            </div>
        </modal>
        <modal v-on-escape="hideSecondModal" v-if="isSecondWindowOpen">
            <p>confirmation window</p>
        </modal>
    </div>
</template>

<script>
export default {
    data () {
        return {
            isFirstWindowOpen: false,
            isSecondWindowOpen: false
        }
    }
    methods: {
        openFormWindow () {
            // form window opens 
            this.isFirstWindowOpen = true
        },
        hideFirstModal () {
            this.isFirstWindowOpen = false
        },
        hideSecondModal () {
            this.isSecondWindowOpen = false
        },
        submitFormOne () {
            // submit the details, let the first window close & open the second window.
            this.isFirstWindowOpen = false
            this.isSecondWindowOpen = true
        }
    }
}
</script>

vue directive on-escape

Vue.directive('on-escape', {
    bind (el, binding, vnode) {
        el.customEventKeydown = function (event) {
            // Check if click was outside the el and his childrens
            if (event.keyCode === 27) {
                vnode.context[binding.expression](event)
            }
        }
        document.body.addEventListener("keydown", el.customEventKeydown)
    },
    unbind (el) {
        document.body.removeEventListener("keydown", el.customEventKeydown)
    }
})
Dan
  • 59,490
  • 13
  • 101
  • 110
htoniv
  • 1,658
  • 21
  • 40

2 Answers2

1

Use a key on each <modal> component to tell Vue not to reuse DOM nodes:

<modal v-on-escape="hideFirstModal" v-if="isFirstWindowOpen" key="modal1">
<modal v-on-escape="hideSecondModal" v-if="isSecondWindowOpen" key="modal2">

Vue was reusing the DOM for the first modal when it created the 2nd, so the second keydown event listener was never created.

When elements are added and removed from the DOM, Vue sometimes tries to help by reusing old DOM nodes to speed up rendering. Sometimes this can have unwanted side effects. The key essentially instructs it not to do this.

Dan
  • 59,490
  • 13
  • 101
  • 110
  • 1
    there are some advantages and disadvantages in using vue vs pure vanilla js, thanks for ur help dude. – htoniv Feb 25 '21 at 08:24
  • Only advantages! :) The DOM reuse thing is an easy snag to fall into when creating directives or anything that manipulates the DOM manually, if using 2+ of the same element sequentially. You're welcome bud – Dan Feb 25 '21 at 08:26
0

It looks like you are missing this.isSecondWindowOpen, it isn't being returned in your data function.

arapl3y
  • 522
  • 8
  • 13