tighten / nova-package-development

A forum for talking about the process of Nova Package Development
52 stars 2 forks source link

Nova Action Index Field Package #44

Closed dillingham closed 5 years ago

alexbowers commented 6 years ago

I have found a way to make a modal open on the index page on an action. I'll publish how once I work out any kinks with it.

DianaR19 commented 6 years ago

What package is it?

Gaia-Nutrition commented 5 years ago

@alexbowers Could you share how you managed to open the Modal? The problem I currently face is the fact that the <action-selector> components (which I could overwrite) only mounts if one or more resources are selected. I was trying to overwrite the <action-selector> component and use Nova.$on() to listen for global events triggered from inside a custom field...

alexbowers commented 5 years ago

Sure @Gaia-Nutrition @dillingham

This was a work in progress that I haven't touched in a while, but I assume that the fundamentals still are there for it to work.

In an IndexField.vue file, I have something like the following:

<template>
    <span>
        <span class="inline-block w-3 cursor-pointer" @click.prevent="openConfirmationModal">
            <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path d="M20 18.35V19a1 1 0 0 1-1 1h-2A17 17 0 0 1 0 3V1a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v4c0 .56-.31 1.31-.7 1.7L3.16 8.84c1.52 3.6 4.4 6.48 8 8l2.12-2.12c.4-.4 1.15-.71 1.7-.71H19a1 1 0 0 1 .99 1v3.35z"/></svg>
        </span>

        <transition name="fade">
            <phone-call-modal 
                v-if="confirmActionModalOpened"
                @close="closeConfirmationModal"
            />
        </transition>

        {{ field.value }}
    </span>
</template>

<script>
    import PhoneCallModal from './PhoneCallModal';

    export default {
        props: ['resourceName', 'field'],
        components: {
            'phone-call-modal': PhoneCallModal,
        },
        data() {
            return {
                confirmActionModalOpened: false,
            }
        },
        methods: {
            openConfirmationModal() {
                this.confirmActionModalOpened = true
            },

            closeConfirmationModal() {
                this.confirmActionModalOpened = false
            },
        },
    }
</script>

And in a PhoneCallModal.vue file I have

<template>
    <modal
        class="modal"
        tabindex="-1"
        role="dialog"
        @modal-close="handleClose"
    >
        <div class="bg-white rounded-lg shadow-lg overflow-hidden w-460">
            <h2 class="pt-8 px-8">Making phone call</h2>
            <p class="text-80 px-8 my-8">This is my message</p>

            <div class="bg-30 px-6 py-3 flex">
                <div class="flex items-center ml-auto">
                    <button
                        type="button"
                        class="btn btn-default btn-primary"
                        @click="makeCall"
                    >
                        <span>Start Call</span>
                    </button>
                </div>
            </div>
        </div>        
    </modal>
</template>

<script>
    import Modal from '@/components/Modal';

    export default {
        components: {
            'modal': Modal,
        },
        props: {
            phoneNumber: String,
        },
        created() {
            this.init();
        },
        methods: {
            makeCall() {
                // ... Do something
            },
            init() {
                // ... Do something
            },
            /**
             * Stop propogation of input events unless it's for an escape or enter keypress
             */
            handleKeydown(e) {
                if (['Escape', 'Enter'].indexOf(e.key) !== -1) {
                    return
                }

                e.stopPropagation()
            },

            /**
             * Execute the selected action.
             */
            handleConfirm(e) {
                this.$emit('confirm')
            },

            /**
             * Close the modal.
             */
            handleClose() {
                this.$emit('close')
            },
        },
    }
</script>

<style scoped>
    .w-460 {
        width: 460px;
    }
</style>

You'll notice the @/components/Modal line, this refers to a component built into Nova JS.

To get it to work like that I have modified the webpack.mix.js file to have the following:


let mix = require('laravel-mix')

mix.js('resources/js/field.js', 'dist/js')
.webpackConfig({
    resolve: {
        symlinks: false,
        alias: {
            '@': path.resolve(__dirname, 'vendor/laravel/nova/resources/js/'),
        },
    }
});

This isn't strictly necessary, since you could work your way to the nova JS files yourself in the modal itself, however, I find this easier to deal with since you can refactor code moving the files around without that action itself causing things to break.

wemersonrv commented 5 years ago

I made a package https://github.com/dillingham/nova-button 🚀

Actions are on the todo list, but it has event support You can accomplish most with events

Please add actions support!