javascriptvue.jsvuetify.js

How to close v-select on click outside v-app?


I have an vue app that user vuetify. The app is used inside existing cms. When a dropdown select is opened a click outside the app does not close the dropdown. If the click is inside the app region, the dropdown closes.

Any idea how can I trigger close for the opened dropdown on click outside the app ?

new Vue({
  el: '#cartbutton',
  data() {
    return {
      items: [{text:'a'}, {text:'b'}]
    }
  }
})
.existing-cms {
  padding: 40px 50px;
}

#app {
  background-color: rgba(0,0,0,0.2);
  padding: 10px;
  height: 200px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<link href="https://unpkg.com/vuetify/dist/vuetify.min.css" rel="stylesheet"/>
<script src="https://unpkg.com/vuetify/dist/vuetify.min.js"></script>
<link href="https://fonts.googleapis.com/css?family=Material+Icons" rel=stylesheet>

<div class="existing-cms">
  <p>Click on the select dropdown and leave it open.</p>
  <p>
    Click on this white region outside the app should somehow close
    opened select in the app.
  </p>
  
  <div id="cartbutton">
    <v-app>
      <span>Clicking here insde the app closed the opened select</span>
      <br><br>
      <v-select label="Click me and leave it opened. Then click in the white region." :items="items"></v-select>
    </v-app>
  </div>
  
</div>

Here is a codepen link https://codepen.io/darkopetreski/pen/OGMvop

EDIT:

It seems that this is reported as a bug here https://github.com/vuetifyjs/vuetify/issues/3144 and the suggestion is to use data-app="true" at the root element, but this approach is not good, since it will mess up stuff (at least was not working well for me).


Solution

  • This is a rather hacky solution but it seems to work. There are two changes:

    1) Add a window click listener that calls the blur method on the v-select. This hides the control. To facilitate this I added a ref to the v-select component.

    2) To prevent this firing when they click inside the app or on the v-select, I added a stop propagation @click.stop onto the container.

    https://codepen.io/anon/pen/BeoOMz

    new Vue({
      el: '#cartbutton',
      data() {
        return {
          items: [{text:'a'}, {text:'b'}]
        }
      },
      mounted() {
        window.addEventListener("click",() => {
           this.$refs.select.blur();
        });    
      }
    })
    .existing-cms {
      padding: 40px 50px;
    }
    
    #app {
      background-color: rgba(0,0,0,0.2);
      padding: 10px;
      height: 200px;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
    <link href="https://unpkg.com/vuetify/dist/vuetify.min.css" rel="stylesheet"/>
    <script src="https://unpkg.com/vuetify/dist/vuetify.min.js"></script>
    <link href="https://fonts.googleapis.com/css?family=Material+Icons" rel=stylesheet>
    
    <div class="existing-cms">
      <p>Click on the select dropdown and leave it open.</p>
      <p>
        Click on this white region outside the app should somehow close
        opened select in the app.
      </p>
      
      <div id="cartbutton" @click.stop>
        <v-app>
          <span>Clicking here insde the app closed the opened select</span>
          <br><br>
          <v-select ref="select" label="Click me and leave it opened. Then click in the white region." :items="items"></v-select>
        </v-app>
      </div>
      
    </div>