-
-
Save blackfyre/ccd2a207948912594b5ac6cf67a11ef8 to your computer and use it in GitHub Desktop.
<template> | |
<modal @modal-close="handleClose"> | |
<form | |
@submit.prevent="handleConfirm" | |
slot-scope="props" | |
class="bg-white rounded-lg shadow-lg overflow-hidden" | |
style="width: 460px" | |
> | |
<slot :uppercaseMode="uppercaseMode" :mode="mode"> | |
<div class="p-8"> | |
<heading :level="2" class="mb-6">{{ __('General Modal') }}</heading> | |
<p class="text-80 leading-normal">{{__('General modal contents')}}</p> | |
</div> | |
</slot> | |
<div class="bg-30 px-6 py-3 flex"> | |
<div class="ml-auto"> | |
<button type="button" data-testid="cancel-button" dusk="cancel-general-button" @click.prevent="handleClose" class="btn text-80 font-normal h-9 px-3 mr-3 btn-link">{{__('Cancel')}}</button> | |
<button id="confirm-delete-button" ref="confirmButton" data-testid="confirm-button" type="submit" class="btn btn-default btn-danger">{{ __(uppercaseMode) }}</button> | |
</div> | |
</div> | |
</form> | |
</modal> | |
</template> | |
<script> | |
export default { | |
name: "GeneralModal", | |
methods: { | |
handleClose() { | |
this.$emit('close') | |
}, | |
handleConfirm() { | |
this.$emit('confirm') | |
}, | |
}, | |
/** | |
* Mount the component. | |
*/ | |
mounted() { | |
this.$refs.confirmButton.focus() | |
}, | |
} | |
</script> | |
<style scoped> | |
</style> |
<template> | |
<div> | |
<button @click="openModal">{{__('Open Modal')}}</button> | |
<portal to="modals"> | |
<transition name="fade"> | |
<general-modal | |
v-if="modalOpen" | |
@confirm="confirmModal" | |
@close="closeModal" | |
/> | |
</transition> | |
</portal> | |
</div> | |
</template> | |
<script> | |
import GeneralModal from './parts/modals/GeneralModal.vue'; | |
export default { | |
props: ["resourceName", "resourceId", "field"], | |
data() { | |
return { | |
modalOpen: false | |
} | |
}, | |
components: { | |
GeneralModal | |
}, | |
mounted() { | |
}, | |
methods: { | |
openModal() { | |
this.modalOpen = true; | |
}, | |
confirmModal() { | |
this.modalOpen = false; | |
}, | |
closeModal() { | |
this.modalOpen = false; | |
} | |
} | |
}; | |
</script> |
Almost a year later and this is still useful. Thank you! 👯♀️ 🎉 🎆
@blackfyre thanks 🙏 😊
Thanks
I'm new to vue.js and laravel. Can somebody explain to me what the portal component does?
@tomscholz
If I remember correctly this is the package in question: https://github.com/LinusBorg/portal-vue
It essentially allows you to render html outside of the component.
If you're interested, I can throw up a general modal component as well... but this one is for Laravel Nova Tools.
@blackfyre
You're missing the modal component as well ^^'.
As the title and the previous comment states this modal solution is for Laravel Nova tools, and expects and relies on Nova's original modal component to be present. This gist only enables you to utilize that modal component at your leisure.
Hi. I'm new to vueJs. Can anyone, please, tell me how to use? where put what code?
@henryavila This isn't for a general Vue.js application! This snippet expects to be in an environment provided by Laravel Nova.
If you're interested in a general use modal component for Vue.js, I strongly suggest you check out the examples section in the docs: https://vuejs.org/v2/examples/modal.html
Thanks for quick response @blackfyre. In fact I'm using Laravel Nova. I'm new in VueJS and automatically the way Laravel Nova use it. I'm a backend (php) developer starting with the frontend with Laravel Nova.
If you could give some direction, I will be so gald.
For example. I create a Card in Laravel Nova. And whant this card to display a Modal. In this case, the Tool.vue
in your gist represent my Card vue file? Then where do I put the GeneralModal.vue
(from your gist) file?
@henryavila
Thanks for the background, this puts things into perspective 😄
Haven't developed a Card before, but the match between the Card & Tool vue files seems reasonable.
As for placing the GeneralModal.vue
file is totally up to you! At some point, you'll have to reference it in your card vue file.
Hello everyone, today i face one problem that I can't use improted component inside this <modal>
tag, maybe I do something wrong, I wanted to use vuedraggable to make some functionality inside my project, but i couldn't because <draggable>
tag is not initialize like draggable component. After I tried to make my own component just with test content like "Hello world" and import that component and use it inside <modal>
tag, the same result. Laravel Nova
If i need two modals in my tool.vue, i need to make two but this does not work I mean if i have two components GeneralModal and TableModal both using difference betwen componentes is only the contenu in the Nova modal's slot, how could I have two modals ?
thanks for this mehn
Thank you for your sharing; I fixed it for Nova 4 like this:
Similar to your implementation but changed to match laravel/nova/resources/js/components/Modals/DeleteResourceModal.vue
GeneralModal.vue
<template>
<Modal @modal-close="handleClose"
:show="show"
role="alertdialog"
size="sm">
<form
@submit.prevent="handleConfirm"
class="mx-auto bg-white dark:bg-gray-800 rounded-lg shadow-lg overflow-hidden"
>
<slot/>
<ModalFooter>
<div class="ml-auto">
<LinkButton
type="button"
data-testid="cancel-button"
dusk="cancel-delete-button"
@click.prevent="handleClose"
class="mr-3"
>
{{ __('Cancel') }}
</LinkButton>
<LoadingButton
ref="confirmButton"
dusk="confirm-delete-button"
:processing="working"
:disabled="working"
component="DangerButton"
type="submit"
>
{{ confirmButtonText }}
</LoadingButton>
</div>
</ModalFooter>
</form>
</Modal>
</template>
<script setup>
import {ref, watchEffect} from 'vue'
const props = defineProps({
confirmButtonText: {
type: String,
default: 'Delete'
}
})
const emit = defineEmits(['close', 'confirm'])
const confirmButton = ref(null)
watchEffect(() => {
// Only focus when mounted (e.g. if hidden through :show)
if (confirmButton.value) {
confirmButton.value.focus()
}
})
const handleClose = () => {
emit('close')
};
const handleConfirm = () => {
emit('confirm')
};
</script>
Tool.vue
...
<GeneralModal
:show="modalOpen"
confirmButtonText="Delete"
@close="closeModal"
@confirm="confirmModal">
<ModalHeader>Delete resource</ModalHeader>
<ModalContent>
<p class="leading-normal">
Are you sure you want to delete the resource?
</p>
</ModalContent>
</GeneralModal>
...
@bmoex thanks for the snippet. any idea how to trigger the auto close on click away functionality? I can see that Nova 4 native modals have it
@bmoex thanks for the snippet. any idea how to trigger the auto close on click away functionality? I can see that Nova 4 native modals have it
You really can't do that without modifying the nova code as it usually involves a click listener on the backdrop.
freakin' lifesaver. Thank you for this.