Vuejs generic modal dialog components for Electron apps

I’m experimenting with Electron as a platform for web-apps that run native and with Vuejs as a dynamic data-binding view component framework. I like both of these software “eco-systems” a lot but I haven’t been satisfied with the solutions for components providing modal dialogs that I’ve found online. (For example, this one or this one.)

Electron supports a dialog element, which is a much better solution than a DIV with high z-index value. Not only that, many of the solutions I’ve seen require a list of Booleans that control whether or not each modal dialog is visible or not; this clutters up the main Vue application object.

My own solution leverages the ability to have a dynamically-bound component: this is either a special “null” dialog or one of the actual working modal dialog windows. Each of the real dialog windows uses a generic dialog component as a child, to handle some of the common functions, and can pass in a class to modify the size of the dialog box. The params object is used for communication of dialog-specific data between the code that uses the dialog and the logic within the dialog itself. Each dialog template can pass a CSS class to modify its size as needed.

I hope this proves useful to others developing on Electron.

(PS: Apologies: WordPress won’t format all of the HTML text content in this blog post properly, so once I have this on GitHub or jsfiddle or something, I’ll post a link. But you should get the idea.)

CSS file

dialog {
    border: 1px grey solid;
    padding: 20px;
    box-shadow: 10px 10px 5px -7px rgba(0,0,0,0.75);
}

dialog div.dialogmedium {
    width: 350px;
}

dialog div.dialogwide {
    width: 500px;
}

HTML file

<!-- Vue app here -->
<template id="vue-modal-generic">
    <dialog id="modal-wrapper">
    </dialog>
</template>

<template id="vue-modal-null">
    <modal :params="params"></modal>
</template>

<template id="vue-modal-test">
    <modal :params="params" mclass="dialogmedium">

[These are buttons that won’t format on this blog, but they send event messages] OK Cancel

    </modal>
</template>

JavaScript file

var VModalGeneric = Vue.extend({
    props: {
        params: Object,
            mclass: {
                type: String,
                default: ''
            }
        },
    template: '#vue-modal-generic',
        // Lifecycle Methods
    ready: function()
    {
        if (this.params.createDialog) {
            document.getElementById("modal-wrapper").showModal();
        }
    },
    beforeDestroy: function()
    {
        if (this.params.createDialog) {
            document.getElementById("modal-wrapper").close();
        }
    }
});

var VModalNull = Vue.extend({
    props: {
       params: Object
    },
    template: '#vue-modal-null',
    components: {
        modal: VModalGeneric
    },
    created: function() {
         this.params.createDialog = false;
    }
});

var VModalTest = Vue.extend({
    props: {
        params: Object
    },
    template: '#vue-modal-test',
    components: {
        modal: VModalGeneric
    },
    created: function() {
        this.params.createDialog = true;
    },
        // Event messages sent by DOM elements
    methods: {
        clickok: function()
        {
                // Add logic here
            this.$dispatch('close-modal');
        },
        clickcancel: function()
        {
            this.$dispatch('close-modal');
        }
     } // methods()
});

var vApp = new Vue({
    el: '#vue-app',
    data: {
        modalParams: { }, // parameters passed to modals
        modalShowing: 'modalNull' // modal currently showing
    },
    components: {
        modalNull: VModalNull,
        modalTest: VModalTest
    },
        // Methods called by DOM elements
    methods: {
            // PURPOSE: Activate a modal, or use 'modalNull'
        setModal: function(modalID)
        {
            this.modalShowing = modalID;
        }
    },
           // Messages sent by child components
    events: {
        'close-modal': function()
        {
            this.modalShowing = 'modalNull';
        },
        'cancel': function () {
            this.editComponent = 'editNull';
            this.itemEditing = null;
            this.indexSelected = -1;
        }
    } // events
});

// To use, set needed parameters in vApp.modalParams and call vApp.setModal('modalTest');

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s