Jenesius / vue-modal

🖖The progressive and simple modal system for Vue.js v3
https://modal.jenesius.com
MIT License
145 stars 14 forks source link

Vue.use(Modal) support? #90

Closed DucNguyenVan closed 6 months ago

DucNguyenVan commented 10 months ago

Hi, thank you for your great library. I am switching from vue-js-modal to vue-modal. In vue-js-modal, I was able to set up like below:

import VModal from 'vue-js-modal'
import { createApp } from 'vue'
const app = createApp(options)
app.use(VModal)

How could I import vue-modal in the same way? (without using template <widget-container-modal />)

import VModal from 'jenesius-vue-modal'  // like this
import { createApp } from 'vue'
const app = createApp(options)
app.use(VModal)
Jenesius commented 10 months ago

@DucNguyenVan, Hi! Thank you for your words of gratitude. Did I understand correctly that you do not have access to the App.vue component and cannot insert a container there:

<template>
    // Othe code
    <container />
</template>
<script setup>
    import {container} from "jenesius-vue-modal";
</script>

If this method does not suit you, give me a couple of hours and I will add the ability to use .use.

DucNguyenVan commented 10 months ago

@Jenesius yes, I do not have access to the App.vue (I dont have App.vue file) I have an existing HTML markup file and integrating Vue into that file.

If this method does not suit you, give me a couple of hours and I will add the ability to use .use.

Thank you so much

Jenesius commented 10 months ago

hmm, it doesn't look so easy now. I'm still thinking of a more elegant solution, but the following will also work:

import {createApp, createVNode} from "vue"
import App from "./App.vue";
import {container} from "jenesius-vue-modal";

createApp(App)
.use({
  install(app) {
    const savedRender = app._component.render;
    const fakeRender = function (...attr) {
      return [ savedRender(...attr), createVNode(container, {}) ]
    }
    app._component.render = fakeRender;
  }
})
.mount("#app")

This is not a solution to your problems, I continue to work within the framework of this task. But it will work as a quick hot-fix. Do you have a public repo where I can see how vue-js-modal work with existing html project?

Jenesius commented 10 months ago

Okay, You integrate Vue inside your project. Something like this. I will create a test project for test it.

DucNguyenVan commented 10 months ago

@Jenesius

Do you have a public repo where I can see how vue-js-modal work with existing html project?

Sorry, I don't have a public repo

I'm still thinking of a more elegant solution, but the following will also work:

Thank you, I will test it

Okay, You integrate Vue inside your project. Something like this.

Yes, I'm using Vue 3 as a Standalone way

DucNguyenVan commented 10 months ago

@Jenesius I tested this solution, but it didn't work :( https://github.com/Jenesius/vue-modal/issues/90#issuecomment-1789303525 Here is the error log. I noticed that app._component.render was returning undefined, which I suspect might be the reason the script isn't functioning.

entry.js:26 Uncaught TypeError: Cannot read properties of undefined (reading 'apply')
    at Proxy.fakeRender
    at renderComponentRoot (runtime-core.esm-bundler.js:1187:1)
Jenesius commented 10 months ago

@DucNguyenVan Can you send me your main.ts/js file. Also you can try just it:

    const fakeRender = function (...attr) {
      return [ createVNode(container, {}) ]
    }
    app._component.render = fakeRender;
DucNguyenVan commented 10 months ago

@Jenesius Here is my main.js

import {openModal, container} from "jenesius-vue-modal";
import store from "./store.js";
import { createApp, createVNode } from 'vue/dist/vue.esm-bundler.js'
import MyModal from "./MyModal";

const createCommonApp = (options) => {
  const app = createApp(options)
  app.use(store)
  app.use({
    install(app) {
      const fakeRender = function (...attr) {
        return [ createVNode(container, {}) ]
      }
      app._component.render = fakeRender;
    }
  })
  return app
}

document.addEventListener("DOMContentLoaded", () => {
  createCommonApp({
    components: {
      MyModal
    },
    methods: {
      openDetailModal(){
        openModal(MyModal);
      }
    },
  })
  .mount('#app')
});

Also you can try just it: const fakeRender = function (...attr) { return [ createVNode(container, {}) ] } app._component.render = fakeRender;

And I tried it, but after app._component.render = fakeRender;, it replaced my entire existing HTML contents.

DucNguyenVan commented 10 months ago

@Jenesius I found a way to make it work as a quick hot-fix. In the HTML file, I add <widget-container-modal /> to the last line (so it will not replace existing HTML contents), and it works as expected!

index.html

<div id="app">
   # other html contents
   <widget-container-modal />
</div>

main.js

import {openModal, container} from "jenesius-vue-modal";
import store from "./store.js";
import { createApp, createVNode } from 'vue/dist/vue.esm-bundler.js'
import MyModal from "./MyModal";

const createCommonApp = (options) => {
  const app = createApp(options)
  app.use(store)
  return app
}

document.addEventListener("DOMContentLoaded", () => {
  createCommonApp({
    components: {
      MyModal,
      WidgetContainerModal: container
    },
    methods: {
      openDetailModal(){
        openModal(MyModal);
      }
    },
  })
  .mount('#app')
});
Jenesius commented 10 months ago

@DucNguyenVan This solution already somewhat resembles a standard one. Can you describe how you use Vue in your project? I would like to document this problem and can suggest a more elegant solution (via using .use). How you build your project.

DucNguyenVan commented 10 months ago

@Jenesius My project uses Rails, webpack, and Vue 3. Vue 3 was used as a standalone way, like this: https://github.com/Jenesius/vue-modal/issues/90#issuecomment-1792118041.

Project structure is almost like this: https://alfianeffendy.medium.com/setup-single-page-application-in-rails-with-vue-3-and-typescript-vue-cli-7bb498069d16.

anshirko commented 10 months ago

@DucNguyenVan Very interesting link. I tried to familiarize myself with how Vue is built into the application in this case. Of course, it would be simpler in the case of an open repository, however, due to the fact that a large number of technologies are used, this can be quite expensive.

In the case of vue-js-modal, a separate instance of Vue is created, but for the Vue3 version this will not work. The exact location of the container must be specified. However, I need to experiment with .use and I’m thinking of adding it to the functionality of this library.

In your case, the example given is an absolutely correct solution to this problem. Very similar to creating a global component. Thus, your solution is the simplest and most correct, another solution:

import {container} from "jenesius-vue-modal"
const app = createApp(options)
app.use(store)
app.component('widget-container-modal', container)
return app

And then also add it to html. But your method is shorter.


@jenesius , Did You found something?