vuejs3vue-componentvuetify.jsvuetifyjs3

Vuetify 3 | how we can close dailog programtically with composable


hi i am doing crud in vuetify 3 and for create form i am using v-dailog, i wanted to close v-dailog once form save data to server successfully. i have used composable to handle my all logics. let me share my code.

My component file

RoleOperations.vue

<template>
    <v-dialog max-width="800">
      <template v-slot:activator="{ props: activatorProps }">
        <v-btn
          v-bind="activatorProps"
          :text="btnTitle"
          @click="getAllPermissions(roleId)"
        ></v-btn>
      </template>

      <template v-slot:default="{ isActive }">
        <v-card :title="modalTitle">
          <template v-slot:text>
            <div v-if="loading" class=" d-flex justify-center">
              <v-progress-circular indeterminate></v-progress-circular>
            </div>
            <v-form v-else @submit.prevent="handleSubmit(roleId)">
              <v-row>
                <v-col cols="12">
                  <v-text-field
                  v-model="form.name"
                  :error-messages="errorMessages.name"
                  autofocus
                  label="Role Name"
                  type="text"
                  placeholder="Administrator Role"
                />
                </v-col>
                <v-col cols="12">
                  <div class="d-flex justify-space-between">
                    <h5>Role Permissions</h5>
                    <v-checkbox v-model="isSelectAllPermissions" @update:model-value="selectAllPermissions" label="Select All"></v-checkbox>
                  </div>
                  <v-container>
                    <v-row no-gutters>
                      <v-col v-for="permission in lstPermissions" :key="permission.id" cols="3">
                        <v-checkbox :value="permission.id" :label="permission.name" v-model="form.permissions"></v-checkbox>
                      </v-col>
                    </v-row>
                    <v-row no-gutters>
                      <v-col class="text-sm text-error">
                      {{ errorMessages.permissions }}
                      </v-col>
                    </v-row>
                  </v-container>
                </v-col>
              </v-row>
              <v-row>
                <v-col cols="12">
                  <v-btn
                  :text="roleId == 0 ? 'save':'update'"
                  variant="elevated"
                  type="submit"
                  class="mr-2"
                  :loading="formLoading"
                >
                <template v-slot:loader><v-progress-circular indeterminate></v-progress-circular> Save</template>
                </v-btn>
                <v-btn
                  text="Cancel"
                  variant="tonal"
                  @click="isActive.value = false"
                ></v-btn>
                </v-col>
              </v-row>
            </v-form>
          </template>
        </v-card>
      </template>
    </v-dialog>
</template>
<script setup lang="ts">

import { useRoleOperations } from '@/composable/useRoleOperations';
  const props = defineProps<{
          btnTitle: string,
          modalTitle:string,
          roleId:number
       }>()
  const { 
    lstPermissions,
    loading,
    getAllPermissions,
    form,
    errorMessages,
    handleSubmit,
    formLoading,
    selectAllPermissions,
    isSelectAllPermissions
    } = useRoleOperations();
</script>

My composeable file

useRoleOperations.ts

import { IPermissionsList, IRole } from "@/Interfaces/IRole";
import { fetchAllPermissions, fetchRoleByID, saveRole, updateRole } from "@/services/RolesService";
import { toast } from 'vue3-toastify';

export function useRoleOperations (){
    
    const lstPermissions = ref<IPermissionsList>([]);
    const loading = ref<boolean>(false);
    const formLoading = ref<boolean>(false);
    const isSelectAllPermissions = ref<boolean>(false);
    const form = ref<IRole>({
        name:'',
        permissions:[]
    });

    const selectAllPermissions = () => {
        if(isSelectAllPermissions.value == true){
            isSelectAllPermissions.value = true;
            form.value.permissions = lstPermissions.value.map(({id}) => id);
        }
        if(isSelectAllPermissions.value == false){
            form.value.permissions = []
            isSelectAllPermissions.value = false;
        }
        
    }
    const errorMessages = ref<[name:string, permissions: string]>([]);

    const getAllPermissions = (id:number) => {
        form.value.name= '';
        form.value.permissions=[];
        loading.value = true;

        //get all permissions
        fetchAllPermissions().then((res) => {
            
            lstPermissions.value = res.data.data
            
            //get selected permissions in role edit case
            if(id != 0){
                fetchRoleByID(id).then((res) => {
                    let data = res.data.data;
                    form.value.name = data.name;
                    form.value.permissions = data.permissions.map(({id}) => id);

                    if(form.value.permissions.length  == lstPermissions.value.length){
                        isSelectAllPermissions.value = true;
                    }
                }).catch((err) => {
                    toast.error(err.message)
                    loading.value = false;
                 })
            }

            loading.value = false;
            }).catch((err) => {
            toast.error(err.message)
            loading.value = false;
         })
        
    }

    const handleSubmit = (id:number) => {
        formLoading.value = true;
        if(id == 0){
            saveRole(form.value).then((res) => {
                formLoading.value = false;
            toast.success(res.data.message)
            })
            .catch((err) => {
              if(err.response.status == "422"){
                errorMessages.value =  err.response.data.errors
                formLoading.value = false;
              }else if(err.response.status == "401"){  
                toast.error(err.response.data.message);
                formLoading.value = false;
                errorMessages.value = ['','']
              }else{
                toast.error(err.message)
                formLoading.value = false;
              }
            })
        }else{
            updateRole(id,form.value).then((res) => {
                formLoading.value = false;
            toast.success(res.data.message)
            })
            .catch((err) => {
              if(err.response.status == "422"){
                errorMessages.value =  err.response.data.errors
                formLoading.value = false;
              }else if(err.response.status == "401"){  
                toast.error(err.response.data.message);
                formLoading.value = false;
                errorMessages.value = ['','']
              }else{
                toast.error(err.message)
                formLoading.value = false;
              }
            })
        }

        // here i wanted to close V-DAILOG programatically
    }
    return {
        lstPermissions,
        loading,
        getAllPermissions,
        selectAllPermissions,
        handleSubmit,
        errorMessages,
        isSelectAllPermissions,
        formLoading,
        form
    }
}

looking forward for help.


Solution

  • isActive slot prop controls the dialog. You are already using it to close the dialog with the cancel button. Simply pass isActive as another parameter to your submit function so you can set it to false.

    <template v-slot:default="{ isActive }">
      ...
      <v-form v-else @submit.prevent="handleSubmit(roleId, isActive)">
    
    const handleSubmit = (id:number, isActive:Ref<boolean>) => {
      ...
      isActive.value = false
    }
    

    If that doesn't work, change the submit to call a local function that calls your composable as the first line and set isActive to false as the next line.