1

I'm using Materialize CSS to design my web app, and I want to display the links based on whether or not a user is authenticated. I can easily check this, but when I add a v-if to my dropdown button, it no longer works.

Here's my code:

<template>
  <ul id="account" class="dropdown-content" v-if="auth">
    <li><a href="#!" class="black-text"><i class="material-icons right">check_circle</i>Link 1</a></li>
    <li><a href="#!" class="black-text"><i class="material-icons right">folder</i>Link 2</a></li>
    <li><a href="#!" class="black-text"><i class="material-icons right">settings</i>Link 3</a></li>
  </ul>
  <nav class="white" role="navigation">
    <div class="nav-wrapper container black-text">
      <ul class="right hide-on-med-and-down">
        <li><a v-if="auth" class="dropdown-button" data-activates="account">{{ auth.first_name }} {{ auth.last_name }}<i class="material-icons right">arrow_drop_down</i></a></li>
        <li><a v-if="auth"><i class="material-icons right">exit_to_app</i>Logout</a></li>
        <div v-if="!auth">
          <li>
            <a v-link="{ name: 'registration' }">
              <i class="material-icons right">create</i>
              Sign Up
            </a>
          </li>
          <li>
            <a v-link="{ name: 'authentication' }">
              <i class="material-icons right">fingerprint</i>
              Login
            </a>
          </li>
        </div>
      </ul>
    </div>
  </nav>
</template>

If I remove the v-ifs, the dropdown opens and closes successfully. I've event looked in the Chrome code inspector, and the code appears but fails to work.

I've also suspected that the classes needed to be bound using v-bind, but this did not help at all.

Jerome Carter
  • 237
  • 1
  • 4
  • 18
  • 1
    Notice that materialize dorpdown uses materialize js file, which depend on jQuery. And also, try to change your `v-if` directives with `v-show` directives. The `v-if` manipulate the DOM, so that might conflict with the js logic of materialize, on the other hand the `v-show`directive only show/hide elements – Yerko Palma Jun 30 '16 at 03:53

1 Answers1

6

This is happening because materialize dropdowns require some jquery to be initialized. Normally this runs on-load, but if you are dynamically adding elements to the DOM you need to handle it yourself.

You can find out how to do this in the materialize docs.

Specifically when using vue, you may want to set up a watch for your auth variable. Whenever auth is changed, be sure to apply the initialization code to the newly created dropdowns.

Here is a snippet demonstrating how to rebind. Make the dropdown disappear and reappear by toggling the v-if. Notice how the dropdown will not work until it is rebound.

var app = new Vue({
  el: '#app',
  
  data: {
    show: true
  },
  
  methods: {
    rebindDropdown: function() {
      $('.dropdown-button').dropdown();  
    }
  },
  
  ready: function() {
    $('.dropdown-button').dropdown();  
  }
});
<link href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.6/css/materialize.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.6/js/materialize.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/1.0.26/vue.js"></script>


<div id="app">

  <button @click="show = !show">Toggle v-if</button>
  <button @click="rebindDropdown">Rebind Dropdown</button>
   
  <div v-if="show">
    <!-- Dropdown Trigger -->
    <a class='dropdown-button btn' href='#' data-activates='dropdown1'>Drop Me!</a>

    <!-- Dropdown Structure -->
    <ul id='dropdown1' class='dropdown-content'>
      <li><a href="#!">one</a></li>
      <li><a href="#!">two</a></li>
      <li><a href="#!">three</a></li>
    </ul>
  </div>

</div>

Finally, here is an example showing how to watch a variable, and automatically rebind when that variable changes.

var app = new Vue({
  el: '#app',
  
  data: {
 show: true
  },
  
  watch: {
    'show': function() {
      console.log('The value for "show" has changed. Rebinding dropdown...');
      $('.dropdown-button').dropdown();
    }
  },
  
  ready: function() {
 $('.dropdown-button').dropdown();  
  }
});
<link href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.6/css/materialize.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.6/js/materialize.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/1.0.26/vue.js"></script>


<div id="app">

  <button @click="show = !show">Toggle v-if</button>
   
  <div v-if="show">
 <!-- Dropdown Trigger -->
 <a class='dropdown-button btn' href='#' data-activates='dropdown1'>Drop Me!</a>

 <!-- Dropdown Structure -->
 <ul id='dropdown1' class='dropdown-content'>
   <li><a href="#!">one</a></li>
   <li><a href="#!">two</a></li>
   <li><a href="#!">three</a></li>
 </ul>
  </div>

</div>
asemahle
  • 20,235
  • 4
  • 40
  • 38
  • Thank you for this great answer. Would you mind showing me how to achieve this without the buttons? – Jerome Carter Jun 30 '16 at 20:16
  • Added another snippet showing how to trigger rebinding by using `watch`. You may also want to look into the [$nextTick](http://vuejs.org/api/#vm-nextTick) callback. Remember: you want to call the jQuery function *after* the dropdown has been added to the page. That's what you're trying to accomplish. – asemahle Jun 30 '16 at 21:01
  • Thank you, I really appreciate the quick answer. This works perfectly, and I can't thank you enough @asemahle – Jerome Carter Jun 30 '16 at 21:53