2

I cannot search for child component DOM element, my settings are as follows:

pages/Login.vue

<template>
 <section class="login">
    <div v-show="step === 4" class="login__container">
      <Test />
    </div>
  </section>
</template>

<script>
export default {
  data () {
    return {
      step: 1
    }
  },
  async mounted () {
      this.step = 4 
      await this.$nextTick()
      document.querySelector('.test') // NULL
  },
}
</script>

components/Test.vue

<template>
  <div class="test">
    foo
  </div>
</template>

setTimeout of course is not solution. I also try the same on other page, but without success. What am I doing wrong? I guess the problem must be somewhere in the template or project configuration

@edit

i tried to do the same effect on jsfiddle vue template and fresh nuxt project but no problem there

JanuszO
  • 1,140
  • 12
  • 25
  • I'm not sure what you're trying to achieve here, but be careful with this kind of logic. This is usually not the recommended way to go. Also yeah, `setTimeout` is never really a great solution! – kissu Aug 19 '21 at 10:05
  • usually I use refs, but I rewrote that quickly, my mistake – JanuszO Aug 19 '21 at 10:10

4 Answers4

2

This kind of code should work properly

parent.vue

<template>
  <div>
    <test ref="parentTest" @hook:mounted="selectChildElement"></test>
  </div>
</template>

<script>
export default {
  methods: {
    selectChildElement() {
      console.log(this.$refs.parentTest.$refs.test)
    },
  },
}
</script>

Test.vue component

<template>
  <div ref="test">foo</div>
</template>

This is because of the way the parent and children components are mounted, as explained here: https://stackoverflow.com/a/44319825/8816585


As Brahim said, it is also better to use $refs in an SPA context, more info available here.

The @hook:mounted trick was taken from this answer and initially found in this dev.to post.

tony19
  • 125,647
  • 18
  • 229
  • 307
kissu
  • 40,416
  • 14
  • 65
  • 133
  • Your approach is correct and I have used it so far, but my logic does not fit that approach a bit. And I have finally found the answer. – JanuszO Aug 19 '21 at 10:57
1

Another way to access child component is emitting event when its ready and created in DOM,

In the child element:

    <template>
      <div ref="test">foo</div>
    </template>
    <script>
    export default {
      mounted() {
        this.$emit('childMounted', this.$refs.test)
      }
    }
    ...

In your parent:

    <template>
     <section class="login">
        <div v-show="step === 4" class="login__container">
          <Test @childMounted="childMounted"/>
        </div>
      </section>
    </template>
    
    <script>
    export default {
      data () {
        return {
          step: 1
        }
      },
      methods: {
       childMounted(childRef) {
         // Try here 
         // childRef: your child component reference
       }
      }
    }
    </script>
Batuhan
  • 1,521
  • 12
  • 29
0

You could try to use ref instead of querySelector to manipulate the component DOM :

<template>
 <section class="login">
    <div v-show="step === 4" class="login__container">
      <Test ref="test"/>
    </div>
  </section>
</template>

<script>
export default {
  data () {
    return {
      step: 1
    }
  },
  mounted () {
      this.step = 4 
   
      let test=this.$refs.test
  },
}
</script>
Boussadjra Brahim
  • 82,684
  • 19
  • 144
  • 164
0

As I thought, the problem is with nuxt, namely auto-importing components. I am using automatic component import in the nuxt configuration.

nuxt.config.js

  components: [
    {
      path: '~/components',
      pathPrefix: false,
    },
  ],

This approach apparently breaks something, and only after manually importing the component did it work properly

import Test from '@/components/Test.vue'

export default {
  name: 'LoginPage',
  components: {
    Test
  },

So the nuxt configuration caused the problem. Thank you for all your help.

JanuszO
  • 1,140
  • 12
  • 25