Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to modify the value of v-model property via custom directive?

When I use custom directive to change component's value, there is not effect:

Vue.directive('maxchars', {
  bind(el, binding, vnode) {
    let maxChars = binding.value;
    let handler = function(e) {
      if (e.target.value.length > maxChars) {
        e.target.value = e.target.value.substr(0, maxChars)
      }
    }
    el.addEventListener('input', handler);
  }
});
let app = new Vue({
  el: '#app',
  data() {
    return {
      content: '',
      totalCount: 140
    }
  }
})
<script src="https://unpkg.com/[email protected]/dist/vue.js"></script>
<div id='app'>
  <div>
    <div class='content'>
      <textarea v-model='content' v-maxchars='140'>tell me something</textarea>
    </div>
  </div>
</div>

when I use v-bind:input directive to change value is ok!

like image 800
mail G Avatar asked Apr 01 '18 13:04

mail G


People also ask

Can we use computed property in v-model?

The combination of the v-model and computed property makes your code robust and more reusable. Hope this article helps you to understand how to use two-way data binding in Vue. js by using the v-model directive and computed properties.

What is v-model directive?

The v-model is a two-way binding which means if you change the input value, the bound data will be changed. The v-model directive is used to create two-way data bindings on form input, textarea, and select elements. Example: HTML.

Can we use v-model in Div?

You can use v-model with a custom Vue component by accepting a prop named 'value' and emitting an event named 'input'. For example, the below custom component is a fake select using div elements. Clicking on a div selects it.

What is V-bind value?

but v-bind:value is called one way binding that means: you can change input value by changing bound data but you can't change bound data by changing input value through the element. ' if you change input value, the bound data will be changed and vice versa.


2 Answers

First:

  • You are using v-model, the value of the textarea will be whatever is in the v-model's variable (in this case, the variable content). This means that the initial value of the DOM is ignored.
  • To handle this, I moved (see below) the string from the DOM declaration to the content in data().

Second:

  • Vue does not respond to changes in .value directly. v-model actually watches for input✱ events from the DOM element.
    • ✱ it actually varies depending on the type of element, sometimes it is the change event, or other
  • If you just set the value, Vue will simple override it back (to whatever is in content) next time an update happens.

Solution:

After changing the .value, trigger input event. Vue will pick the event up and update the v-model variable from the current .value before it overrides it.

Demo:

Vue.directive('maxchars', {
  bind(el, binding, vnode) {
    let maxChars = binding.value;
    let handler = function(e) {
      if (e.target.value.length > maxChars) {
        e.target.value = e.target.value.substr(0, maxChars);
        vnode.elm.dispatchEvent(new CustomEvent('input')); // added this
      }
    }
    el.addEventListener('input', handler);
  }
});
let app = new Vue({
  el: '#app',
  data() {
    return {
      content: 'tell me something',
      totalCount: 140
    }
  }
})
<script src="https://unpkg.com/[email protected]/dist/vue.js"></script>
<div id='app'>
  <div>
    <div class='content'>
      <textarea v-model='content' v-maxchars='18'></textarea>
    </div>
    <pre>
    content: {{ content }}
    Max chars is 18, current is {{ content.length }}.
    </pre>
  </div>
</div>
like image 79
acdcjunior Avatar answered Sep 23 '22 18:09

acdcjunior


Just create a input event using Event function.

var event = new Event("input", { bubbles: true });

then modify the value and then dispatch the event, it will update the v-model value

el.dispatchEvent(event);

Vue.directive('maxchars', {
  update(el, binding, vnode) {
    var event = new Event("input", { bubbles: true });
    let maxChars = binding.value;
      if (el.value.length > maxChars) {
        el.value = e.value.substr(0, maxChars);
        el.dispatchEvent(event);
      }
  }
});

hope it will helpful.

like image 36
Shaik Matheen Avatar answered Sep 21 '22 18:09

Shaik Matheen