I have dug through many solutions for handling modals in Vue.js but unfortunately none was exactly right for my purposes. So here it is — next way of creating dynamic modals in Vue.js. Featuring vue-like data binding & typed data passing.
For the record, this is a fairly new approach to modals making for me, which may lead to unexpected bugs or other problems that I’m not aware yet. I will try to update the article if any major issues comes up.
Firstly, my main goal in creating this system was to achieve rather simple creation of components and data binding that follows original vue-like pattern based on events.
Modal constructor accepts root component in order to append modal HTML on top of it, which should solve depth problems with having many pop ups at once.
Second param accepts all kind of data that we would like to pass. Thanks to the interface it holds types of all possible information that given modal handles.
After its initialization, modal is automatically rendered. That could be moved to a separate function but let’s keep it simple here.
Next there is classic vue-like data binding that prevents direct data mutation.
And that sets it up, let’s see what’s behind it.
The most tricky part with implementing it to me was to discover the VueConstructor interface. I seems that there is no information about it on the official Vue documentation. Correct me if I’m wrong, maybe I missed something.
We start with simple interface to ensure that we will pass all things that our component requires. As we won’t be doing any static data passing I allowed myself to create PropsData only. We will extend it later on.
ModalService is where the fun begins. As we don’t want it to be instantiated directly we will implement it as an abstract class.
We are exposing adding event listeners and destroying component. It is important to note that it should also expose some other methods like, at least removing event listeners.
Constructor takes root component as mentioned above. VueConstructor which stands for exported class from our .vue component, and any interface that extends ModalData.
We are passing data to component constructor to bind everything we need. Then there is event registration to have some way of closing the modal. At the end we are mounting it and rendering HTML.
Now it’s time for some hot boilerplate.
Since we are extending ModalData we have a pretty good type imitation! Which is still not the best solution but hundred times better than having to remember all needed data / props when there is a necessity to create a modal.
Also with component permanently bound to data we are preventing from typos and bugs. Unfortunately, as I said, it requires some boilerplate but at least not the biggest one.
To stitch it all together here is a very ̶u̶g̶l̶y̶ minimalistic modal component with ‘value’ prop.
For anyone unfamiliar with PropSync decorator I’ll send you here.
If I didn’t make any typos this code should compile just fine.
Of course it needs a lot of polish to become a truly good modular system for modals but it works perfectly fine as a proof of concept. If you don’t want to reinvent the wheel just go download some robust package and you will be ready to go.
After all I hope that you understand the idea behind it.
Let’s end with optimistic accent — all my concerns about performance of this system.
As I’m aware it doesn’t work with default Vue caching in any way.
That is something that should be kept in mind. Also if someone would like to throw to the project this basic implementation that I written above I assume that each calling for displaying would basically be an initialization of a new component and then destroying it upon closing modal, which to me sounds like a big no-no.
If the modal would be toggle very often it should be implemented in a way that resembles how vue original directives work — v-show.
And last but not least if you are editing .vue of a modal and then save, your already initialized component on scene won’t rerender itself. There is no classic reactivity as far as I know.
To be honest with myself I must credit Konrad Straszewski for his article on modular modals, which was a cornerstone for me coming up with this solution.
Update 18.05.2020 — I’ve move code to github gists.