1

I am using a v-for loop and using a Vue.directive for a bootstrap tooltip which sets the binding value a string which I return from a method. How do I change this binding value once I have new data? It does not update even when I have new data returned from my method.

I have tried making a data variable and setting this in my method and using the variable in my directive and it still didn't change.

Vue.directive('tooltip',
        function(el, binding) {
            $(el).tooltip({
                title: binding.value,
                placement: binding.arg,
                trigger: 'hover'
            });
        });


<li v-for="(display_name, index) in displayNameList" class="nav-item">
    <a v-tooltip:bottom="tabTooltipSet(index)" {{ display_name }}</a>
</li>

I expect the binding.value to change to whatever the function returns when called, which it does initially. But after that value has been set and my displayNameList can completely change it does not update accordingly. So if my first tab is set to DOG and then I change the list and set it to CAT the tooltip should be CAT instead of DOG.

  • from the docs: bind: called only once, when the directive is first bound to the element. This is where you can do one-time setup work – Bergur Jul 10 '19 at 01:41
  • Have you put console logging inside that function? Is it not being called at all when the data changes or is it being called again with the wrong value? Personally I'm suspicious of the `$(el).tooltip`, not sure how that would behave if you called it again on the same element. – skirtle Jul 10 '19 at 09:49
  • @Bergur That's just it I need to do this more than once (when the data changes) I might be completely misusing the directive, but I am not sure what I need at this moment. – Turtle_Code Jul 10 '19 at 14:41
  • @skirtle it is being called again with the correct value, but the binding value isn't changing even though the correct value is being passed in after the data changes. Any ideas on a work around? – Turtle_Code Jul 10 '19 at 14:43
  • @Turtle_Code I don't really understand, you say the value is correct and then you say it isn't. If the value of `binding.value` is correct inside that function then there is no Vue problem here. More likely the problem is with `$(el).tooltip`. Try using `$(el).tooltip('dispose')` to get rid of the old tooltip before you add the new one. – skirtle Jul 10 '19 at 15:29
  • @skirtle I am sorry if I am not being very clear I am new to Vue. Basically I can step through every time I hover over a tab it resets all my tooltips which isn't ideal, but it passes the value to binding.value correctly. Yet I hover over the tabs again the tooltip is incorrect. I want that once I click a button I set all the tooltips right then and there. I am extending this SO [link](https://stackoverflow.com/q/37078423/11665640) . The code I am using for my directive is from Ikbel's answer which is the answer below the accepted. The difference is I am using multiple tooltips from a v-for. – Turtle_Code Jul 10 '19 at 17:30

1 Answers1

0

The Vue directive seems to be working correctly. The problem is calling tooltip() twice on the same element won't update the tooltip. In my example I've just destroyed the previous tooltip and added a new one. There might be less heavy-handed ways of doing this but it seemed the simplest way to achieve the desired outcome.

Vue.directive('tooltip', function(el, binding) {
  if (binding.value === binding.oldValue) {
    return
  }

  $(el).tooltip('dispose')

  $(el).tooltip({
    title: binding.value,
    placement: binding.arg,
    trigger: 'hover'
  });
});

new Vue({
  el: '#app',
  
  data () {
    return {
      displayNameList: ['Red', 'Green', 'Blue'],
      tooltipNumber: 0
    }
  },
  
  methods: {
    onClick () {
      this.tooltipNumber++
    },

    tabTooltipSet (index) {
      return this.displayNameList[index] + ' tooltip ' + this.tooltipNumber
    }
  }
})
.nav-item {
  background: #ccc;
  border: 1px solid #000;
  list-style: none;
  margin: 10px auto;
  width: 100px;
}

.nav-item a {
  display: block;
}
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
<script src="https://unpkg.com/vue@2.6.10/dist/vue.js"></script>

<div id="app">
  <ul>
    <li v-for="(display_name, index) in displayNameList" class="nav-item">
      <a v-tooltip:bottom="tabTooltipSet(index)">{{ display_name }}</a>
    </li>
  </ul>
  <button @click="onClick">Update tooltips</button>
</div>

I've included a check for whether the value has changed to avoid unnecessarily creating/destroying the tooltip. A more robust version would need to check whether the placement has changed too. You should also handle destroying the tooltips properly using the directive's unbind hook as it seems likely there'd be leaks without that.

skirtle
  • 27,868
  • 4
  • 42
  • 57