javascriptjqueryvue.jsvuejs2

Why does not Vue model update when input.val(value)?


I have editable table:

<div id="myTable">
   <b-table class="overflow-auto" :items="filtered" :fields="visibleFields" :filter="filter">
        <template v-for="field in editableFields" v-slot:[`cell(${field.key})`]="{ item }">
            <b-input v-model="item[field.key]" placeholder="--" @@change="update" />
        </template>
    </b-table>
</div>

Vue script(cdn)

    <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.10/vue.js"></script>
    <script src="https://unpkg.com/bootstrap-vue@2.4.1/dist/bootstrap-vue.min.js"></script>
    <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
    <script src="https://unpkg.com/axios/dist/axios.min.js"></script>

    <script>


        new Vue({
            el: "#myTable",
            computed: {
                editableFields() {
                    return this.fields.filter(field => field.editable);
                },
                visibleFields() {
                    return this.fields.filter(field => field.visible)
                }
            },
            data: {
                filter: '',
                filtered: JSON.parse(`@Html.Raw(Model.SportBudgetsJson)`),
                fields: [
                    { key: 'Id', label: 'Id', visible: false },
                    { key: 'Field1', label: 'Field1', editable: true, visible: true, class: "percentageFormat pValue", thStyle: { width: "5%" } },
                    { key: 'Field2', label: 'Field2', editable: true, visible: true, class: "moneyFormat mValue", thStyle: { width: "10%" } },

                ]
            }
        });
...

And js functions for formatting values in the table:

 function formatValue(value, event, isPercent) {
     ... // returns value in ###.##% or $###,###.## format
     return formattedValue;
 }

 function copyValue(element, isPercent) { //update in % value if $'s value have changed and vise versa
     var selector = isPercent ? '.mValue' : '.pValue';
     var input = $(element).parent('td').parent('tr').children(selector).first().children('input');
     var value = element.value.replace(/[^\d]+/g, '');
     value = converValue([value.slice(0, -2), '.', value.slice(-2)].join(''), isPercent);
     $(input).val(formatValue(value, 'input', !isPercent));
 }

 function converValue(value, isPercent) {
     value = parseFloat(value);
     var totalBudget = parseFloat(`@Model.TotalBudget`);
     if (isPercent) {
         return parseFloat(totalBudget * (value / 100)).toFixed(2);
     }
     else {
         return parseFloat(value / totalBudget * 100).toFixed(2);
     }
 }
     
 $(document).ready(function () { // apply format events
     $('.moneyFormat input').each(function (index, el) {
         $(el).val(formatValue(el, "input", false));
         $(el).on("input change", function (event) {
             $(this).val(formatValue($(this).val(), event, false));
             if ($(el).parent('td').first().hasClass('mValue'))
                 copyValue(this, false);
         });
     });

     $('.percentageFormat input').each(function (index, el) {
         $(el).val(formatValue(this, "input", true));
         $(el).on("input change", function (event) {
             $(this).val(formatValue($(this).val(), event, true));
             if ($(el).parent('td').first().hasClass('pValue')) {
                 copyValue(this, true);
             }
         });
     });
 });

when I use $(input).val(formatValue(value, 'input', !isPercent)) value in the table updates, but v-model not. but when I type the value to input manually - v-model updates

I want to implement real-time values update: Total sum $100.00 Field1: changes from 12.00% to 13.00% so Field2 automaticly changes from $12.00 to $13.00

Total sum $100.00 Field2: changes from $50.00 to $45.00 so Field1 automaticly changes from 50.00% to 45.00%

The values should calculates and pastes to their inputs

How can I update v-model to inputs values?


Solution

  • JQuery manipulation of the DOM doesN't automatically update Vue reactive data binding because Vues reactivity system relies on its own methods to detect changes to data When you directly manipulate the DOM with jquery Vue is unaware of these changes.

    function copyValue(element, isPercent) { 
        var selector = isPercent ? '.mValue' : '.pValue';
        var row = $(element).closest('tr'); 
        var input = row.find(selector).first().children('input');
        var value = element.value.replace(/[^\d]+/g, '');
        value = converValue([value.slice(0, -2), '.', value.slice(-2)].join(''), isPercent);
      
        var index = row.index(); 
        if (isPercent) {
      
            this.filtered[index].Field1 = value; 
        } else {
            this.filtered[index].Field2 = value; 
        }
        input.val(formatValue(value, 'input', !isPercent));
    }