Search code examples
javascripthtmlcssvue.jsmaterialize

V-If Conflicts With Materialize CSS Dropdown Button


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.


Solution

  • 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>