0

I'm trying to identify the click outside of my element who is a speed dial item from vuetify. In order to do that, I'm using directives from this solution to solve my problem `Detect click outside element. I am able to click outside and get a log to verify it but I also get the log 'clicked outside' whenever i click inside of my element. How can i prevent my directive to click inside of the element as well? I do have log statement to check when click outside is triggered. I tried stopping the event bubbling or event propagation in case if it's related to that but that did not help. Thank you!

<template>
    <v-card>
        <v-speed-dial
            v-click_outside="outside"
            :bottom="true"
            :right="true"
            :direction="direction"
            :transition="transition"
            fixed
        >
        <template v-slot:activator>
            <v-btn
                :class="{ is_active: isActive }"
                color="red"
                fab
                @click="toggleButton"
                dark
                x-large
            > 
                <span  v-if="isActive"><v-icon>mdi-pencil</v-icon></span>
                <v-icon v-else>mdi-plus </v-icon>
            </v-btn>
        </template>
            <v-btn 
                fab 
                dark 
                large 
                color="white" 
                @click.stop="$emit('scrollTo')">
                <v-icon color="#F0BE85">mdi-delete</v-icon>
            </v-btn>
        </v-speed-dial>
    </v-card>
</template>

<script>

export default {
name: 'FloatingButton',
props: {
    display: Boolean,
    ott: Boolean,
    preroll: Boolean,
    gt: Boolean
},
data: () => ({
    direction: 'top',
    fab: false,
    right: true,
    bottom: true,
    transition: 'scale-transition',
    isActive: false,
    backgroundColor: false
}),
methods: {
    toggleButton: function () {
    this.isActive = !this.isActive
    this.backgroundColor = !this.backgroundColor
    },
    outside:function(){
        console.log('clicked outside')
    }
},
directives: {
click_outside:{
    bind:function(el,binding,vnode){
        el.clickOutsideEvent=function(event){
            if (!(el == event.target || el.contains(event.target))) {
                    vnode.context[binding.expression](event);
            }
        }
        document.body.addEventListener('click',el.clickOutsideEvent)
    }
},
unbind:function(el){
    document.body.removeEventListener('click',el.clickOutsideEvent)
}
}
}
</script>
curiosityrock
  • 213
  • 4
  • 20

1 Answers1

0

It doesn't work because the "plus" or "pencil" icon that is targeted by the event no longer exists by the time you check for el.contains(), because v-if switched that element for another.

Instead, use this so the element stays the same :

<v-btn :class="{ is_active: isActive }" color="red" fab @click="toggleButton" dark x-large>
  <v-icon>{{ isActive ? 'mdi-pencil' : 'mdi-plus' }}</v-icon>
</v-btn>
Renaud
  • 1,290
  • 8
  • 8
  • Hmm that worked but i don't understand why removing v-if has a role for clicking outside. As you probably noticed, click outside directive is in v-speed-dial, not in icon. Why does it matter if that icon targeted by event is no longer exist, in other words why do we target those icons? Shouldn't target the container element v-speed-dial. Also, do you know how could i add a text next to icon when it's active e.g {{ isActive ? 'mdi-pencil' + "ADD ITEM" : 'mdi-plus' }} something like this, but this doesn't work @Renaud Thanks for the answer, have a good weeekend! – curiosityrock May 16 '20 at 15:14
  • Solved adding the text part but I still wonder why removing v-if helps this working – curiosityrock May 16 '20 at 15:23
  • _"Why does it matter if that icon targeted by event is no longer exist"_ : because `el.contains(event.target)` returns true in that case. Btw event.target is just the element you clicked on – Renaud May 16 '20 at 15:59