How to close child dialog dynamically



  • Hi, i have a parent component that creates a child dialog and I would like to close the dialog dynamically from the child. I have tried many things but it doesn’t work.

    Parent

    <template>
            <q-dialog
              v-model="signInDialog"
              @closeSignInDialog="signInDialog = false"
              persistent
              transition-show="flip-down"
              transition-hide="flip-up"
            >
              <login></login>
            </q-dialog>
    </template>
    <script lang="ts">
    import Login from 'components/Login.vue'
    import { defineComponent, ref } from '@vue/composition-api';
    
    export default defineComponent({
      name: 'MainLayout',
      data () {
        return {
          signInDialog: false
        }
      },
      components: { Login },
      setup() {
        const leftDrawerOpen = ref(false);
    
        return {leftDrawerOpen}
      }
    });
    </script>
    

    Child:

    methods: {
        async onSubmit () {
          await dispatchLogIn(this.$store, {username: this.email, password: this.password})
          if (readLoginError(this.$store)) {
            // fail
            this.$q.notify({
              color: 'negative',
              position: 'top',
              message: 'Incorrect email or password',
              icon: 'report_problem'
            })
          }else{
    ---->        this.$emit("closeSignInDialog")
          }
        }
      },
    });
    

    What am I doing wrong ?



  • @lesourcil

    What if you put the code from your login component directly in your q-dialog? Does it work then?

    If so maybe this will help:
    https://github.com/quasarframework/quasar/issues/5822



  • @dobbel
    Im not sure I understand, if I copy my login component (child) directly into my q-dialog (parent) then i wont have a child/parent, only parent so it should work ?



  • @lesourcil

    Well yes because every thing( including the on submit code) is in 1 component so you don’t have to emit events. You can change signInDialog directly:

    async onSubmit () {
          await dispatchLogIn(...)
          if (readLoginError(this.$store)) {
            // fail
            this.$q.notify({
              color: 'negative',
              position: 'top',
              message: 'Incorrect email or password',
              icon: 'report_problem'
            })
          }else{
    ---->        this.signInDialog = false   <---
          }
        }
    


  • @dobbel

    ok let me clarify. These are 2 different vue files. (im a noob in vue)

    Parent: pages/main.vue

    <template>
            <q-dialog
              v-model="signInDialog"
              @closeSignInDialog="signInDialog = false"
              persistent
              transition-show="flip-down"
              transition-hide="flip-up"
            >
              <login></login>
            </q-dialog>
    </template>
    <script lang="ts">
    import Login from 'components/Login.vue'
    import { defineComponent, ref } from '@vue/composition-api';
    
    export default defineComponent({
      name: 'MainLayout',
      data () {
        return {
          signInDialog: false
        }
      },
      components: { Login },
      setup() {
        const leftDrawerOpen = ref(false);
    
        return {leftDrawerOpen}
      }
    });
    </script>
    

    Child : components/Login.vue

    <template>
    ...
    </template>
    <script>
    ...
    
    methods: {
        async onSubmit () {
          await dispatchLogIn(this.$store, {username: this.email, password: this.password})
          if (readLoginError(this.$store)) {
            // fail
            this.$q.notify({
              color: 'negative',
              position: 'top',
              message: 'Incorrect email or password',
              icon: 'report_problem'
            })
          }else{
    ---->        this.$emit("closeSignInDialog")
          }
        }
      },
    });
    </script>
    

    I don’t want to move my code from login.vue component to main.vue page.

    Does it makes sens ?



  • @lesourcil

    I don’t want to move my code from login.vue component to main.vue page.

    Ah I see.

    I personally use Vuex to solve these kind of problems. I am not a vue event expert, but using a q-dialog with custom components requires some extra work:

    https://github.com/quasarframework/quasar/issues/5822



  • @dobbel

    I just figured it out because you made me think. You rock!

    I ended moving my <dialog> into my login component itself and then adding a props “showDialog” that i can set from parent

    Child : components/Login.vue

    <template>
      <q-dialog
    --->    v-model="showDialog"
        persistent
        transition-show="flip-down"
        transition-hide="flip-up"
      >
    
    ...
    
    </template>
    <script>
    ...
    
    props: {
    -->    showDialog: {
          default: false,
          type: Boolean,
        },
      },
    
    methods: {
        async onSubmit () {
          await dispatchLogIn(this.$store, {username: this.email, password: this.password})
          if (readLoginError(this.$store)) {
            // fail
            this.$q.notify({
              color: 'negative',
              position: 'top',
              message: 'Incorrect email or password',
              icon: 'report_problem'
            })
          }else{
    --->        this.showDialog = false
          }
    ...
    </script>
    

    and then on parent : pages/main.vue

    <template>
      <login :showDialog="showSignInDialog"></login>
    </template>
    <script>
    ...
    
    data () {
        return {
          showSignInDialog: false
        }
      },
    
    </script>
    
    


  • @lesourcil

    Great! Yes that’s also a way to prevent using events.

    I thought a little about it and I might know what the problem is in your original code. From Vue’s perspective the q-dialog is the parent of your custom login component.

    Because your login component is emitting the event you should also let your login component expose the @closeSignInDialog instead of your q-dialog:(I might be totally wrong here)

    <template>
            <q-dialog
              v-model="signInDialog"
              persistent
              transition-show="flip-down"
              transition-hide="flip-up"
            >
              <login @closeSignInDialog="signInDialog = false"></login>
            </q-dialog>
    </template>
    

    A better name for the event would be ‘loginSucces’ or something since the login component is not aware of it’s parent q-dialog.



  • @dobbel

    Yup it makes sense, but I think I prefer to have my dialog inside my component.

    And I like your name suggestion for the event.

    Thx again for your help.


Log in to reply