Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Vue Directive: Dynamically Replacing an element with a component – Event Listeners Not Working

I’m working on a Vue 3 project where I need to dynamically replace anchor elements that contain a specific attribute (data-button) with a custom Vue component (CustomButton). To achieve this, I created a directive that queries all the anchor tags within a specified element and dynamically imports the CustomButton component. Below link is a simplified version of my implementation:
[you can see a simiplified example here]

Directive (parser-directive.js):

import { nextTick } from 'vue';
import { loadCustomButton } from './dynamic-import-custom-button.js';

const htmlParserDirective = {
    async mounted(el) {
        await nextTick();
        console.log('Directive inserted');

        const wrapper = document.createElement('div');
        wrapper.innerHTML = el.innerHTML;
        const anchorTags = wrapper.querySelectorAll('a[data-button]');

        if (anchorTags.length) {
            for (const anchor of anchorTags) {
                const text = anchor.innerText.trim();
                const path = anchor.getAttribute('data-path');

                const CustomButton = await loadCustomButton();
                console.log('CustomButton loaded:', CustomButton);

                const CustomButtonComponent = createApp(CustomButton, { text, path });

                const customButtonInstance = CustomButtonComponent.mount(document.createElement('div'));
                console.log('CustomButton instance mounted:', customButtonInstance);

                customButtonInstance.$el.addEventListener('mouseenter', () => {
                    console.log('Mouse Enter');
                });
                customButtonInstance.$el.addEventListener('mouseleave', () => {
                    console.log('Mouse Leave');
                });

                anchor.parentNode.replaceChild(customButtonInstance.$el, anchor);
            }

            el.innerHTML = wrapper.innerHTML;
        }
    },
};

export default htmlParserDirective;

CustomButton.vue:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

    <a :href="path">
        {{ text }}
    </a>
</template>

<script>
export default {
    name: 'CustomButton',
    props: {
        text: {
            type: String,
            default: '',
        },
        path: {
            type: String,
            default: ''
        }
    },
    mounted() {
        console.log('CustomButton mounted');
    },
};
</script>

<style scoped>
a {
    text-decoration: none;
    color: inherit;
    cursor: pointer;
}
</style>

App.vue:

  <div id="app">
    <div v-html-parser>
      <a href="#" data-button data-path="test.test">Test Button</a>
    </div>
  </div>
</template>

<script>
export default {
  name: 'App',
};
</script>

Problem:
The issue I’m facing is that the event listeners for mouseenter and mouseleave are not being triggered. Although I can see that the CustomButton component is loaded and replaced correctly, the added event listeners do not seem to be working.

Question:
Why are the mouseenter and mouseleave event listeners not being triggered on the dynamically created CustomButton component? Is there a different approach or a solution to ensure these event listeners are called?

Any help or suggestions would be greatly appreciated!

>Solution :

You just set pure HTML to the directive’s div. That copies HTML only obviously, no event handlers, you should move the children elements:

            el.innerHTML = '';
            for(const child of wrapper.children){
              el.appendChild(child);
            }
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading