4

How can I write a Vue 2.x directive in such a way that it can detect changes in the model? I can only bind to the element and detect input, keydown, etc. But i can't detect when the model was updated. Is this out of scope for Vue's directives?

 Vue.directive('text-validation', {
        bind: function (el, binding, vnode) {
            el.addEventListener('input', function(){
            	console.log('only gets called on input, not model updates');
            });
        }
    });
    
new Vue({
	el: '#app',
  data: {
  	text: 'testing...'
  },
  mounted: function() {
  	setTimeout(function(){
       this.text = 'detected change';
    }.bind(this), 2000)
  }
})    
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.9/vue.js"></script>

<div id="app">
  <input v-model="text" v-text-validation=""/>
</div>

1

2 Answers 2

7

Ah, I forgot what the update hook is for. I created a working snippet, that does what I intended - an update on model calls the update hook

 Vue.directive('text-validation', {
        bind: function (el, binding, vnode) {
            el.addEventListener('input', function(){
            	console.log('got called');
            });
        },
        update: function(el, binding, vnode) {
        	console.log('got called on upadate');
        }
    });
    
new Vue({
	el: '#app',
  data: {
  	text: 'testing...'
  },
  mounted: function() {
  	setTimeout(function(){
       this.text = 'detected change';
    }.bind(this), 2000)
  }
})    
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.9/vue.js"></script>
<div id="app">
  <input v-model="text" v-text-validation=""/>
</div>

EDIT

I ended up setting up a watch() inside the bind() hook. Firing any kind of DOM native events from inside of update() was causing all sorts of infinite loops.

Pseudocode:

var modelExp = vnode.data.directives.find(d->d.name === 'model');
vnode.context.$watch(modelExp, function(){//do what i need}, {deep, true});

This was borrowed from "VeeValidate" project, ListenerGenerator.prototype._attachModelWatcher

Sign up to request clarification or add additional context in comments.

Comments

1

As @Bert pointed out - you can/could use watchers for that (if you do not need something more advanced - as central state / store Vuex etc.).

With watchers - it is very important to note that you can use them with "deep: true," that watches children inside objects;

watch: {
    myData: {
      handler: function (newVal, oldVal) {
        // we have new and old values
      },
      deep: true /* we will be notified of changes also if myData.child is changed :) */
    }
  }

State is more complicated but can be a saviour if app is getting more and more complex...

Found this usefull and simple demo: Vue - Deep watching an array of objects and calculating the change?

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.