Wossname
Wossname

Reputation: 2171

Vue component $el not in dom when component mounted via v-if

I have a simple popover component, which grab the position of its parent in the dom and then hoists itself into document.body and positions itself absolutely.

This all works great when I show and hide the component using v-show, but if I try to use v-if, it complains that this.$el.parentElement is null.

According to the documentation, $el should be in-document when mounted() is called, but this doesn't appear to be the case when it's rendered conditionally via v-if.

I've tried using nextTick but that doesn't help either.

Am I doing something wrong?

Here's the code for my component:

<template>
<div class="popover"><slot ></slot></div>
</template>

<script>
export default {
    name: 'pop-over',
    props: ['position', 'anchor', 'offset'],
    methods: {

    },
    mounted() {
        let rect = {};
        let parent = this.$el.parentElement;
        document.body.appendChild(this.$el);

        let offset = {
            x: this.offset ? this.offset.x || 0 : 0,
            y: this.offset ? this.offset.y || 0 : 0
        }


        if (this.position) {
            rect = {
                top: this.position.top,
                left: this.position.left
            }
        } else {
            rect = parent.getBoundingClientRect();
            rect = {
                top: rect.top + window.scrollY,
                left: rect.left + window.scrollX,
                bottom: window.innerHeight - rect.bottom - + window.scrollY,
                right: window.innerWidth - rect.right + window.scrollX
            }
        }


        this.$el.style.left = (rect.left + offset.x) + 'px';

        if (this.anchor == 'below') {
            this.$el.style.top = (rect.top + offset.y) + 'px';
        } else {
            this.$el.style.bottom = (rect.bottom + offset.y) + 'px';
        }
    }
}
</script>

Upvotes: 1

Views: 716

Answers (1)

tianjianchn
tianjianchn

Reputation: 731

I was facing the same problem with popup implemention. Finally, solved by the code below:

let elParent = this.$el.parentNode;

if (!elParent) {
  let parent = this.$parent;
  while (parent && parent.$el === this.$el) {
    parent = parent.$parent;
  }

  if (parent) {
    parent.$el.appendChild(this.$el);
    elParent = parent.$el;
  }
}

So what I did is re-building the dom relationship when rendering after v-if=true.

Upvotes: 1

Related Questions