VueJs 2 custom directive closes when outside click doesn't work


Baia

I'm working on a vuejs component that should close if you click outside of a combobox.

My problem is that the custom directive doesn't work, the program compiles, but in the browser I get this error:

[Vue warn]: Error in directive click-outside bind hook: "TypeError: Cannot set property 'event' of undefined"

Here is the code of my component:

<template>
  <div class="form-group" v-click-outside="hide">
  <label v-if="label" for="combobox" class="control-label" v-tack>{{ label }}:</label>
    <input id="combobox"
    class="form-control combo-box-control"
    v-on:keyup="filter(searchText,options)"
    v-model="searchText"
    :placeholder="placeholder"
    v-on:click="showAllOptions()" :disabled="isDisabled">
        <template v-if="showAutocomplete">
        <div class="combobox-list">
            <p class="combobox-options" :key="item.id" v-for="item in listFiltered" v-on:click="optionSelected(item)">{{item.text}}</p>
        </div>
        </template>
  </div>
</template>
<script>
export default {
  data () {
    return {
      listFiltered: [],
      searchText: '',
      showAutocomplete: false
    }
  },
  props: {
    name: { type: String, required: true },
    options: Array,
    label: String,
    isDisabled: { type: Boolean, default: false },
    selectedOption: Object,
    placeholder: String
  },
  methods: {
    filter (word, array) {
      if (word === undefined) {
        this.showAutocomplete = false
        this.listFiltered = []
        return
      }
      this.showAutocomplete = true
      this.listFiltered = array.filter(function (item) {
        return item.text.toLowerCase().includes(word.toLowerCase())
      })
    },
    optionSelected (item) {
      this.searchText = item.text
      this.showAutocomplete = false
      if (item !== undefined) {
        this.$emit('change', { name: this.name, item: item })
      }
    },
    showAllOptions () {
      this.listFiltered = this.options
      this.showAutocomplete = !this.showAutocomplete
    },
    hide () {
      this.showAutocomplete = false
    }
  }
}
</script>
<style>
.form-group{
    position:relative;
}
.form-group input{
    width:100%;
}

input.combo-box-control:active{
  border-style: solid;
  border-width: 1px 1px 0 1px;
  border-radius: 5px 5px 0px 0px;
  border-color: #96c8da;
}

.form-control.combo-box-control:focus{
  border-color: #96c8da;
}

.combobox-list{
    position:relative;
    height:154px;
    width:100%;
    background-color:white;
    overflow-y:auto;
    text-align:justify;
    z-index: 5;
    border-style: solid;
    border-color: #96c8da;
    border-width: 0 1px 1px 1px;
    border-radius: 0px 0px 5px 5px;
    top: -3px;
}

.combobox-options{
    padding:6px 0;
    margin:0;
}
.combobox-options:hover{
    background-color:#d9d9d9;
}
</style>

and main.js:

Vue.directive('click-outside', {
  bind: function (el, binding, vnode) {
    this.event = function (event) {
      if (!(el === event.target || el.contains(event.target))) {
        vnode.context[binding.expression](event)
      }
    }
    document.body.addEventListener('click', this.event)
  },
  unbind: function (el) {
    document.body.removeEventListener('click', this.event)
  }
})

The problem is in the line, which is undefined this.event = function (event) {as the error Cannot set property 'event' of undefinedsays. Not sure how to define it inside the directive.

I'm using this example to get it to work with my custom component: https://jsfiddle.net/Linusborg/yzm8t8jq/ Am I missing something? Update: The code in the original example is from vuejs 1.x, although I found a similar example in vuejs 2.1 https://jsfiddle.net/y0rpfecd/ I am still getting the same error.

Swati

You may have found the answer. Hope someone finds it useful.

I recently tested the click-outside directive in a side project. Just replace this.event with window.event in the directive code. And it works great!

instruction

import Vue from 'vue';

Vue.directive('click-outside', {
    bind: function (el, binding, vnode) {
        window.event = function (event) {
            if (!(el == event.target || el.contains(event.target))) {
                vnode.context[binding.expression](event);
            }
        };
        document.body.addEventListener('click', window.event)
    },
    unbind: function (el) {
        document.body.removeEventListener('click', window.event)
    },
});

To use in a component: just import the directive.

<template>
  <div class="form-group" v-click-outside="hide">
  <label v-if="label" for="combobox" class="control-label" v-tack>{{ label }}:</label>
    <input id="combobox"
    class="form-control combo-box-control"
    v-on:keyup="filter(searchText,options)"
    v-model="searchText"
    :placeholder="placeholder"
    v-on:click="showAllOptions()" :disabled="isDisabled">
        <template v-if="showAutocomplete">
        <div class="combobox-list">
            <p class="combobox-options" :key="item.id" v-for="item in listFiltered" v-on:click="optionSelected(item)">{{item.text}}</p>
        </div>
        </template>
  </div>
</template>
<script>
import clickOutside from '../directive';
export default {
  data () {
    return {
      listFiltered: [],
      searchText: '',
      showAutocomplete: false
    }
  },
  props: {
    name: { type: String, required: true },
    options: Array,
    label: String,
    isDisabled: { type: Boolean, default: false },
    selectedOption: Object,
    placeholder: String
  },
  methods: {
    filter (word, array) {
      if (word === undefined) {
        this.showAutocomplete = false
        this.listFiltered = []
        return
      }
      this.showAutocomplete = true
      this.listFiltered = array.filter(function (item) {
        return item.text.toLowerCase().includes(word.toLowerCase())
      })
    },
    optionSelected (item) {
      this.searchText = item.text
      this.showAutocomplete = false
      if (item !== undefined) {
        this.$emit('change', { name: this.name, item: item })
      }
    },
    showAllOptions () {
      this.listFiltered = this.options
      this.showAutocomplete = !this.showAutocomplete
    },
    hide () {
      this.showAutocomplete = false
    }
  }
}
</script>
<style>
.form-group{
    position:relative;
}
.form-group input{
    width:100%;
}

input.combo-box-control:active{
  border-style: solid;
  border-width: 1px 1px 0 1px;
  border-radius: 5px 5px 0px 0px;
  border-color: #96c8da;
}

.form-control.combo-box-control:focus{
  border-color: #96c8da;
}

.combobox-list{
    position:relative;
    height:154px;
    width:100%;
    background-color:white;
    overflow-y:auto;
    text-align:justify;
    z-index: 5;
    border-style: solid;
    border-color: #96c8da;
    border-width: 0 1px 1px 1px;
    border-radius: 0px 0px 5px 5px;
    top: -3px;
}

.combobox-options{
    padding:6px 0;
    margin:0;
}
.combobox-options:hover{
    background-color:#d9d9d9;
}
</style>

Related


VueJs 2 custom directive closes when outside click doesn't work

Baia I'm working on a vuejs component that should close if you click outside of a combobox. My problem is that the custom directive doesn't work, the program compiles, but in the browser I get this error: [Vue warn]: Error in directive click-outside bind hook:

VueJs 2 custom directive closes when outside click doesn't work

Baia I'm working on a vuejs component that should close if you click outside of a combobox. My problem is that the custom directive doesn't work, the program compiles, but in the browser I get this error: [Vue warn]: Error in directive click-outside bind hook:

Angularjs custom directive on click doesn't work

Jonathan Naxon I have created a custom directive in angularjs: directives.directive('myTop',function($compile) { return { restrict: 'E', templateUrl: 'views/header.html', } }) The code of the instruction: <div class="my-header"> <button ng-click="aler

Angularjs custom directive on click doesn't work

Jonathan Naxon I have created a custom directive in angularjs: directives.directive('myTop',function($compile) { return { restrict: 'E', templateUrl: 'views/header.html', } }) The code of the instruction: <div class="my-header"> <button ng-click="aler

Angularjs custom directive on click doesn't work

Jonathan Naxon I have created a custom directive in angularjs: directives.directive('myTop',function($compile) { return { restrict: 'E', templateUrl: 'views/header.html', } }) The code of the instruction: <div class="my-header"> <button ng-click="aler

VueJs 2 click doesn't seem to work

Dylan Glockler I'm not getting any errors and it's compiling so I'm not sure what I'm doing wrong.I searched for this topic without success. I have BulkExpenses.vue which pulls and displays some expense records, then BulkExpenses.vue is a nested component that

VueJs 2 click doesn't seem to work

Dylan Glockler I'm not getting any errors and it's compiling so I'm not sure what I'm doing wrong. I searched for this topic without success. I have BulkExpenses.vue which pulls and displays some expense records, then BulkExpenses.vue is a nested component tha

VueJs 2 click doesn't seem to work

Dylan Glockler I'm not getting any errors and it's compiling so I'm not sure what I'm doing wrong. I searched for this topic without success. I have BulkExpenses.vue which pulls and displays some expense records, then BulkExpenses.vue is a nested component tha

custom directive doesn't work

Stoffel I am trying to create a directive for edited/private information. If some information is not provided, a black box should be displayed (like the content is there but hidden by the black box) import { Directive, ElementRef, Renderer, OnInit } from '@an

custom directive doesn't work

Stoffel I am trying to create a directive for edited/private information. If some information is not provided, a black box should be displayed (like the content is there but hidden by the black box) import { Directive, ElementRef, Renderer, OnInit } from '@an

custom directive doesn't work

Stoffel I am trying to create a directive for edited/private information. If some information is not provided, a black box should be displayed (like the content is there but hidden by the black box) import { Directive, ElementRef, Renderer, OnInit } from '@an

custom directive doesn't work

Stoffel I am trying to create a directive for edited/private information. If some information is not provided, a black box should be displayed (like the content is there but hidden by the black box) import { Directive, ElementRef, Renderer, OnInit } from '@an

custom directive doesn't work

Stoffel I am trying to create a directive for edited/private information. If some information is not provided, a black box should be displayed (like the content is there but hidden by the black box) import { Directive, ElementRef, Renderer, OnInit } from '@an

ng-click doesn't work when passing function to directive

Sibevin Wang I've tried storing the menu info in an array ( in the example) and rendering menu_entriesit using a directive ( myMenu) , but the functions stored in the array don't seem to work with ng-click. Here is the example : http://jsfiddle.net/5CaQx/ menu

ng-click doesn't work when passing function to directive

Sibevin Wang I've tried storing the menu info in an array ( in the example) and rendering menu_entriesit using a directive ( myMenu) , but the functions stored in the array don't seem to work with ng-click. Here is the example : http://jsfiddle.net/5CaQx/ menu

ng-click doesn't work when passing function to directive

Sibevin Wang I've tried storing the menu info in an array ( in the example) and rendering menu_entriesit with a directive ( myMenu) , but the functions stored in the array don't seem to work with ng-click. Here is the example : http://jsfiddle.net/5CaQx/ menu1

Directive doesn't work outside component

me_digvijay I have an Angular 2 Directivethat looks like this: import { DOM } from 'angular2/src/platform/dom/dom_adapter'; import {Directive, ElementRef, Renderer} from 'angular2/core' @Directive({ selector: '[headerBG]', host: { '(click)': '

vuejs custom directive doesn't seem to be registered

Nick Craft I am building a custom directive which is stored in its own file autosize.js, it looks like this: import Vue from 'vue' import autosize from 'autosize' Vue.directive('autosize', { bind: function() { console.log('autosize bind')

vuejs custom directive doesn't seem to be registered

Nick Craft I am building a custom directive which is stored in its own file autosize.js, it looks like this: import Vue from 'vue' import autosize from 'autosize' Vue.directive('autosize', { bind: function() { console.log('autosize bind')

vuejs custom directive doesn't seem to be registered

Nick Craft I am building a custom directive which is stored in its own file autosize.js, it looks like this: import Vue from 'vue' import autosize from 'autosize' Vue.directive('autosize', { bind: function() { console.log('autosize bind')

vuejs custom directive doesn't seem to be registered

Nick Craft I am building a custom directive which is stored in its own file autosize.js, it looks like this: import Vue from 'vue' import autosize from 'autosize' Vue.directive('autosize', { bind: function() { console.log('autosize bind')

vuejs custom directive doesn't seem to be registered

Nick Craft I am building a custom directive which is stored in its own file autosize.js, it looks like this: import Vue from 'vue' import autosize from 'autosize' Vue.directive('autosize', { bind: function() { console.log('autosize bind')

vuejs custom directive doesn't seem to be registered

Nick Craft I am building a custom directive which is stored in its own file autosize.js, it looks like this: import Vue from 'vue' import autosize from 'autosize' Vue.directive('autosize', { bind: function() { console.log('autosize bind')

Custom validation directive doesn't work

don't know much I wrote a simple instruction to validate numbers. However, if I enter characters in the input field, I never see the error message. http://plnkr.co/edit/pbgVtMI3cT959edrysuA?p=preview <html ng-app="MyCalc"> <head> <script src="//ajax.goo

Custom validation directive doesn't work

don't know much I wrote a simple instruction to validate numbers. However, if I enter characters in the input field, I never see the error message. http://plnkr.co/edit/pbgVtMI3cT959edrysuA?p=preview <html ng-app="MyCalc"> <head> <script src="//ajax.goo

Custom validation directive doesn't work

don't know much I wrote a simple instruction to validate numbers. However, if I enter characters in the input field, I never see the error message. http://plnkr.co/edit/pbgVtMI3cT959edrysuA?p=preview <html ng-app="MyCalc"> <head> <script src="//ajax.goo

Directive doesn't work when using routes

manda bossar See the AngularJS code below dir.js (function() { var myApp = angular.module("MyApp"); myApp.directive('myMovie', function() { return { restrict: 'E', transclude: 'true',

Directive doesn't work when using routes

manda bossar See the AngularJS code below dir.js (function() { var myApp = angular.module("MyApp"); myApp.directive('myMovie', function() { return { restrict: 'E', transclude: 'true',

Directive doesn't work when using routes

manda bossar See the AngularJS code below dir.js (function() { var myApp = angular.module("MyApp"); myApp.directive('myMovie', function() { return { restrict: 'E', transclude: 'true',