skip to Main Content

I’ve finally been able to encapsulate a Vuetify <v-dialog> in a custom component in Vue 3 Composition API. Below is the code for my SignUpDialog.vuecomponent. It’s also available in a Vuetify Play playground.

<script setup>
  import { onMounted } from 'vue'

  const props = defineProps({ modelValue: Boolean })
  const emits = defineEmits(['update:modelValue'])
  function updateModelValue(value) {
    emits('update:modelValue', value)
  }
  onMounted(() => {
    /* Verbose code that initializes firebase ui auth....*/
    // ui.start('#firebaseui-auth-container', uiConfig) 
    /* Fails with error: "Could not find the FirebaseUI widget element on the page." */
  })
</script>

<template>
  <h3>modelValue: {{ modelValue }}</h3>
  <v-dialog :model-value="modelValue" @update:model-value="updateModelValue">
    <v-sheet class="mx-auto">
      <v-card>
        <v-card-title>modelValue: {{ modelValue }}</v-card-title>
        <div id="firebaseui-auth-container"></div>
      </v-card>
    </v-sheet>
  </v-dialog>
</template>

<style scoped></style>

<script></script>

My goal now is to populate the dialog with content from FirebaseUI’s Auth SDK. I’m not including the actual code here because it’s rather verbose. Suffice it to say that it ends with a call to an SDK function that injects HTML into <div id="firebaseui-auth-container"></div>.

I’ve tried running the initialization code in the onMounted event handler and that yields an error that says:

Could not find the FirebaseUI widget element on the page.

I think this is because the dialog is hidden at the time the custom component is mounted and so the <div> does not exist in the DOM yet.

My question is – How can I use idiomatic Vue 3 Composition API to have the initialization code run as soon as the <v-dialog> is rendered so that it succeeds in injecting into the <div>?

2

Answers


  1. A watcher sounds appropriate here. It can run code only once the dialog is rendered, which would be when modelValue is true, so you would watch that value. I’m not familiar with the firebase SDK but in case it only needs to run once you can include a flag variable, e.g. initialized that can be used in an if to only run the code one time.

    let initialized = false
    watch(modelValue, (open) => {
      if (open && !initialized) {
        /* initialize firebase */
        initialized = true
      }
    })
    
    Login or Signup to reply.
  2. You could use VNode hook @vue:mounted on the element then use the handler to init the Firebase widget:

    <script setup>
      import { ref, onMounted, watch } from 'vue'
    
      const props = defineProps({ modelValue: Boolean })
      const emits = defineEmits(['update:modelValue'])
      function updateModelValue(value) {
        emits('update:modelValue', value)
      }
    
      function onContainerMounted(el) {
        //init the widget here
      }
    </script>
    
    <template>
      <h3>modelValue: {{ modelValue }}</h3>
    
      <v-dialog :model-value="modelValue" @update:model-value="updateModelValue">
        <v-sheet class="mx-auto">
          <v-card>
            <v-card-title>modelValue: {{ modelValue }}</v-card-title>
            <div id="firebaseui-auth-container" @vue:mounted="onContainerMounted">
              aa
            </div>
          </v-card>
        </v-sheet>
      </v-dialog>
    </template>
    
    
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search