mdbootstrap / TW-Elements

𝙃𝙪𝙜𝙚 collection of Tailwind MIT licensed (free) components, sections and templates 😎
https://tw-elements.com
MIT License
12.88k stars 1.62k forks source link

How to open a Modal programmatically? #1367

Closed v79 closed 1 year ago

v79 commented 1 year ago

I need to display my modal programmatically, inside a sveltekit Typescript component (i.e. not simply through the data-bs-target attribute on my button). Is this possible?

I've been looking at the commit logs and there seems to be some API documentation coming, but it's not on the tailwind-elements website. And I can't import the library/module into my svelte components. E.g. I can't find a valid import for te:

const myModal = new te.Modal(document.getElementById('save-dialog'), {});
smolenski-mikolaj commented 1 year ago

@v79 please check the docs again and update tw-elements in your project to v1.0.0-beta1. We've just released a new version of our UI KIT and now you should be able to use toggle, show or hide methods in your app as we describe in docs: https://tailwind-elements.com/docs/standard/components/modal/#docsTabsAPI

MattiaLeoni commented 1 year ago

The problem for SvelteKit with the invalid import seems to still be the case. Just updated to the v1.0.0-beta1 and I can't seem to import te correctly

smolenski-mikolaj commented 1 year ago

How did you install our UI KIT in the project? Which type of installation of SvelteKit do you use?

mralston commented 1 year ago

I'm also having trouble getting the modal to work via the API. I'm using the following packages, installed using npm:

"@inertiajs/vue3": "^1.0.0",
"tailwindcss": "^3.2.1",
"vue": "^3.2.41",
"tw-elements": "^1.0.0-beta1"

With the following code:

<script setup>
import 'tw-elements';

const uploadModal = new te.Modal(document.getElementById("uploadModal"), {});

function open()
{
    uploadModal.show();
}

defineExpose({ open });
</script>

The entire page fails to render and I get the following error on the console:

UploadModal.vue:4 Uncaught (in promise) ReferenceError: te is not defined
    at setup (UploadModal.vue:4:17)
    at callWithErrorHandling (runtime-core.esm-bundler.js:173:22)
    at setupStatefulComponent (runtime-core.esm-bundler.js:7265:29)
    at setupComponent (runtime-core.esm-bundler.js:7220:11)
    at mountComponent (runtime-core.esm-bundler.js:5542:13)
    at processComponent (runtime-core.esm-bundler.js:5517:17)
    at patch (runtime-core.esm-bundler.js:5119:21)
    at mountChildren (runtime-core.esm-bundler.js:5303:13)
    at processFragment (runtime-core.esm-bundler.js:5476:13)
    at patch (runtime-core.esm-bundler.js:5112:17)

If I remove import 'tw-elements'; and instead use the script tag:

<script src="https://cdn.jsdelivr.net/npm/tw-elements/dist/js/index.min.js"></script>

I then get a different error:

Uncaught TypeError: Cannot read properties of null (reading 'defaultPrevented')
    at fs.show (modal.js:127:6)
    at Proxy.open (UploadModal.vue:8:21)
    at launchUploadModal (Index.vue:30:27)
    at callWithErrorHandling (runtime-core.esm-bundler.js:173:22)
    at callWithAsyncErrorHandling (runtime-core.esm-bundler.js:182:21)
    at HTMLButtonElement.invoker (runtime-dom.esm-bundler.js:345:9)
aladynjr commented 1 year ago

I'm also having trouble getting the modal to work via the API. i get the error 'te' is not defined

smolenski-mikolaj commented 1 year ago

Can you check if importing js file like this: import * as te from 'tw-elements'; instead of: import 'tw-elements'; fixes the issue?

mralston commented 1 year ago

Can you check if importing js file like this: import * as te from 'tw-elements'; instead of: import 'tw-elements'; fixes the issue?

Hi Mikolaj!

That's an improvement. I can now ditch the <script> tag and it appears to be importing te - no more error about te being undefined.

I am however having the issue about it failing to read defaultPrevented on null. The stack trace is slightly different to the one I posted previously, but I assume that's just down to the usage change in how it's imported.

modal.js:127 Uncaught (in promise) TypeError: Cannot read properties of null (reading 'defaultPrevented')
    at fs.show (modal.js:127:6)
    at Proxy.open (UploadModal.vue:32:21)
    at Index.vue:38:31

Here's the bit I believe that it's referring to:

// ...
    const showEvent = EventHandler.trigger(this._element, EVENT_SHOW, {
      relatedTarget,
    });

    if (showEvent.defaultPrevented) {
      return;
    }
// ...

So it seems like showEvent is null. Should I be passing some sort of context when registering the modal or invoking its show() method? At the moment, this is all I've got:

const uploadModal = new te.Modal(document.getElementById("uploadModal"), {});
uploadModal.show();
MattiaLeoni commented 1 year ago

import * as te from 'tw-elements';

Hi Mikolaj, thanks for the help. Trying that for me results in another error:

Could not find a declaration file for module 'tw-elements'. 'c:/.../node_modules/tw-elements/dist/js/index.min.js' implicitly has an 'any' type.
Try `npm i --save-dev @types/tw-elements` if it exists or add a new declaration (.d.ts) file containing `declare module 'tw-elements';`ts(7016)
smolenski-mikolaj commented 1 year ago

Actually it's only a warning, not an error. We're working on it, but it should not break the app.

smolenski-mikolaj commented 1 year ago

@mralston it looks like the trigger button has wrong code and modal component can't find it. Please check if you have all necessary data-attributes in your html code.

smolenski-mikolaj commented 1 year ago

Closing due to lack of response.

mralston commented 1 year ago

Sorry for the slow response. I've created a simple example of the error using code from the documentation.

<script setup>
import * as te from 'tw-elements';

const myModal = new te.Modal(document.getElementById("exampleModal"));

function openModal()
{
    myModal.show();
}
</script>

<template>

    <!-- Button trigger modal via data attributes (this works) -->
    <button
        type="button"
        class="inline-block rounded bg-primary px-6 pt-2.5 pb-2 text-xs font-medium uppercase leading-normal text-white shadow-[0_4px_9px_-4px_#3b71ca] transition duration-150 ease-in-out hover:bg-primary-600 hover:shadow-[0_8px_9px_-4px_rgba(59,113,202,0.3),0_4px_18px_0_rgba(59,113,202,0.2)] focus:bg-primary-600 focus:shadow-[0_8px_9px_-4px_rgba(59,113,202,0.3),0_4px_18px_0_rgba(59,113,202,0.2)] focus:outline-none focus:ring-0 active:bg-primary-700 active:shadow-[0_8px_9px_-4px_rgba(59,113,202,0.3),0_4px_18px_0_rgba(59,113,202,0.2)] m-5"
        data-te-toggle="modal"
        data-te-target="#exampleModal"
        data-te-ripple-init
        data-te-ripple-color="light">
        Launch demo modal (data attrs)
    </button>

    <!-- Button trigger modal using Javascript (this fails) -->
    <button
        type="button"
        class="inline-block rounded bg-primary px-6 pt-2.5 pb-2 text-xs font-medium uppercase leading-normal text-white shadow-[0_4px_9px_-4px_#3b71ca] transition duration-150 ease-in-out hover:bg-primary-600 hover:shadow-[0_8px_9px_-4px_rgba(59,113,202,0.3),0_4px_18px_0_rgba(59,113,202,0.2)] focus:bg-primary-600 focus:shadow-[0_8px_9px_-4px_rgba(59,113,202,0.3),0_4px_18px_0_rgba(59,113,202,0.2)] focus:outline-none focus:ring-0 active:bg-primary-700 active:shadow-[0_8px_9px_-4px_rgba(59,113,202,0.3),0_4px_18px_0_rgba(59,113,202,0.2)]"
        data-te-ripple-init
        data-te-ripple-color="light"
        @click="openModal">
        Launch demo modal (Javascript)
    </button>

    <!-- Modal -->
    <div
        data-te-modal-init
        class="fixed top-0 left-0 z-[1055] hidden h-full w-full overflow-y-auto overflow-x-hidden outline-none"
        id="exampleModal"
        tabindex="-1"
        aria-labelledby="exampleModalLabel"
        aria-hidden="true">
        <div
            data-te-modal-dialog-ref
            class="pointer-events-none relative w-auto translate-y-[-50px] opacity-0 transition-all duration-300 ease-in-out min-[576px]:mx-auto min-[576px]:mt-7 min-[576px]:max-w-[500px]">
            <div
                class="min-[576px]:shadow-[0_0.5rem_1rem_rgba(#000, 0.15)] pointer-events-auto relative flex w-full flex-col rounded-md border-none bg-white bg-clip-padding text-current shadow-lg outline-none dark:bg-neutral-600">
                <div
                    class="flex flex-shrink-0 items-center justify-between rounded-t-md border-b-2 border-neutral-100 border-opacity-100 p-4 dark:border-opacity-50">
                    <h5
                        class="text-xl font-medium leading-normal text-neutral-800 dark:text-neutral-200"
                        id="exampleModalLabel">
                        Modal title
                    </h5>
                    <button
                        type="button"
                        class="box-content rounded-none border-none hover:no-underline hover:opacity-75 focus:opacity-100 focus:shadow-none focus:outline-none"
                        data-te-modal-dismiss
                        aria-label="Close">
                        <svg
                            xmlns="http://www.w3.org/2000/svg"
                            fill="none"
                            viewBox="0 0 24 24"
                            stroke-width="1.5"
                            stroke="currentColor"
                            class="h-6 w-6">
                            <path
                                stroke-linecap="round"
                                stroke-linejoin="round"
                                d="M6 18L18 6M6 6l12 12" />
                        </svg>
                    </button>
                </div>
                <div class="relative flex-auto p-4" data-te-modal-body-ref>
                    Modal body text goes here.
                </div>
                <div
                    class="flex flex-shrink-0 flex-wrap items-center justify-end rounded-b-md border-t-2 border-neutral-100 border-opacity-100 p-4 dark:border-opacity-50">
                    <button
                        type="button"
                        class="inline-block rounded bg-primary-100 px-6 pt-2.5 pb-2 text-xs font-medium uppercase leading-normal text-primary-700 transition duration-150 ease-in-out hover:bg-primary-accent-100 focus:bg-primary-accent-100 focus:outline-none focus:ring-0 active:bg-primary-accent-200"
                        data-te-modal-dismiss
                        data-te-ripple-init
                        data-te-ripple-color="light">
                        Close
                    </button>
                    <button
                        type="button"
                        class="ml-1 inline-block rounded bg-primary px-6 pt-2.5 pb-2 text-xs font-medium uppercase leading-normal text-white shadow-[0_4px_9px_-4px_#3b71ca] transition duration-150 ease-in-out hover:bg-primary-600 hover:shadow-[0_8px_9px_-4px_rgba(59,113,202,0.3),0_4px_18px_0_rgba(59,113,202,0.2)] focus:bg-primary-600 focus:shadow-[0_8px_9px_-4px_rgba(59,113,202,0.3),0_4px_18px_0_rgba(59,113,202,0.2)] focus:outline-none focus:ring-0 active:bg-primary-700 active:shadow-[0_8px_9px_-4px_rgba(59,113,202,0.3),0_4px_18px_0_rgba(59,113,202,0.2)]"
                        data-te-ripple-init
                        data-te-ripple-color="light">
                        Save changes
                    </button>
                </div>
            </div>
        </div>
    </div>

</template>

Clicking the Javascript button throws the following:

runtime-core.esm-bundler.js:40
[Vue warn]: Unhandled error during execution of native event handler 
  at <ModalTest errors= {} auth= {user: {…}} ziggy= {url: 'http://localhost', port: null, defaults: Array(0), routes: {…}, location: 'http://localhost/modal-test'}  ... > 
  at <Inertia initialPage= {component: 'ModalTest', props: {…}, url: '/modal-test', version: '6666cd76f96956469e7be39d750cc7d9', scrollRegions: Array(0), …} initialComponent= {__name: 'ModalTest', __hmrId: '91af0292', __file: '/Users/matt/Sites/welcome-calls/resources/js/Pages/ModalTest.vue', setup: ƒ, render: ƒ, …} resolveComponent=fn<r>  ... > 
  at <App>
warn2 @ runtime-core.esm-bundler.js:40
logError @ runtime-core.esm-bundler.js:230
handleError @ runtime-core.esm-bundler.js:222
callWithErrorHandling @ runtime-core.esm-bundler.js:176
callWithAsyncErrorHandling @ runtime-core.esm-bundler.js:182
invoker @ runtime-dom.esm-bundler.js:345

runtime-core.esm-bundler.js:236
Uncaught TypeError: Cannot read properties of null (reading 'defaultPrevented')
    at fs.show (modal.js:127:6)
    at openModal (ModalTest.vue:8:13)
    at callWithErrorHandling (runtime-core.esm-bundler.js:173:22)
    at callWithAsyncErrorHandling (runtime-core.esm-bundler.js:182:21)
    at HTMLButtonElement.invoker (runtime-dom.esm-bundler.js:345:9)
vongohren commented 1 year ago

This comes back to the part about importing im not onMount. This library is not fit for SSR and you need to import things onMount to work properly

oldravian commented 10 months ago

I'm not sure why someone closed that issue I still got this error "Uncaught ReferenceError: te is not defined"

vongohren commented 10 months ago

I'm not sure why someone closed that issue I still got this error "Uncaught ReferenceError: te is not defined"

Its an issue and only fixable with onMount hack mentioned earlier

tangyi90 commented 1 month ago

"tw-elements": "^2.0.0", const myModal = new Modal(document.getElementById("myModal")); Uncaught ReferenceError: Modal is not defined

tangyi90 commented 1 month ago

<button type="button" onclick="login()" class="inline-block rounded bg-primary px-6 pb-2 pt-2.5 text-xs font-medium uppercase leading-normal text-white shadow-primary-3 transition duration-150 ease-in-out hover:bg-primary-accent-300 hover:shadow-primary-2 focus:bg-primary-accent-300 focus:shadow-primary-2 focus:outline-none focus:ring-0 active:bg-primary-600 active:shadow-primary-2 dark:shadow-black/30 dark:hover:shadow-dark-strong dark:focus:shadow-dark-strong dark:active:shadow-dark-strong"> {{ __('login') }}

        <script>

        const myModalEl = document.getElementById("exampleModalCenter");
        const modal = new Modal(myModalEl);

        function login() {

            modal.show();
        }
    </script>

    Uncaught ReferenceError: Modal is not defined
    What's going on?
chihabhajji commented 3 weeks ago

facing the same issue in react (pages dir) where the first click triggers a defaultPrevented error but then it works fin (i'm importing it using a useEffect so it imports at the çapp level on first render)