JuniorTour / vue-template-babel-compiler

Enable Optional Chaining(?.), Nullish Coalescing(??) and many new ES syntax for Vue.js SFC based on Babel
https://www.npmjs.com/package/vue-template-babel-compiler
118 stars 9 forks source link

[Bug] Indexing object with v-for variable generates incorrect code. #16

Closed ascott18 closed 2 years ago

ascott18 commented 2 years ago

When using an element of iteration within the loop as an indexer, the iteration variable gets incorrectly generated as an access off of _vm.

In the example below, the particular issue is all occurrences of _vm.actionKey, which should just be actionKey. $$i and $$a also get incorrectly transformed into accesses off of _vm.

Current behavior

With vue-template-babel-compiler 1.0.4:

var render = function() {
  var _vm = this
  var _h = _vm.$createElement
  var _c = _vm._self._c || _h

  return _c(
    "div",
    _vm._l(_vm.actionKeys, function(actionKey) {
      return _c("div", [
        _c("input", {
          directives: [
            {
              name: "model",
              rawName: "v-model",
              value: _vm.enabled[actionKey],
              expression: "enabled[actionKey]"
            }
          ],
          attrs: {
            type: "checkbox"
          },
          domProps: {
            checked: Array.isArray(_vm.enabled[actionKey])
              ? _vm._i(_vm.enabled[actionKey], null) > -1
              : _vm.enabled[actionKey]
          },
          on: {
            change: function change($event) {
              var $$a = _vm.enabled[actionKey],
                $$el = $event.target,
                $$c = $$el.checked ? true : false

              if (Array.isArray($$a)) {
                var $$v = null,
                  $$i = _vm._i($$a, $$v)

                if ($$el.checked) {
                  _vm.$$i < 0 &&
                    _vm.$set(
                      _vm.enabled,
                      _vm.actionKey,
                      _vm.$$a.concat([_vm.$$v])
                    )
                } else {
                  _vm.$$i > -1 &&
                    _vm.$set(
                      _vm.enabled,
                      _vm.actionKey,
                      _vm.$$a
                        .slice(0, _vm.$$i)
                        .concat(_vm.$$a.slice(_vm.$$i + 1))
                    )
                }
              } else {
                _vm.$set(_vm.enabled, _vm.actionKey, $$c)
              }
            }
          }
        })
      ])
    }),
    0
  )
}

Expected behavior

With vue-template-compiler 2.6.11:

function render() {
  var _vm = this;
  var _h = _vm.$createElement;
  var _c = _vm._self._c || _h;
  return _c(
    'div',
    _vm._l(_vm.actionKeys, function (actionKey) {
      return _c('div', [
        _c('input', {
          directives: [
            {
              name: 'model',
              rawName: 'v-model',
              value: _vm.enabled[actionKey],
              expression: 'enabled[actionKey]',
            },
          ],
          attrs: {
            type: 'checkbox',
          },
          domProps: {
            checked: Array.isArray(_vm.enabled[actionKey])
              ? _vm._i(_vm.enabled[actionKey], null) > -1
              : _vm.enabled[actionKey],
          },
          on: {
            change: function ($event) {
              var $$a = _vm.enabled[actionKey],
                $$el = $event.target,
                $$c = $$el.checked ? true : false;
              if (Array.isArray($$a)) {
                var $$v = null,
                  $$i = _vm._i($$a, $$v);
                if ($$el.checked) {
                  $$i < 0 &&
                    _vm.$set(_vm.enabled, actionKey, $$a.concat([$$v]));
                } else {
                  $$i > -1 &&
                    _vm.$set(
                      _vm.enabled,
                      actionKey,
                      $$a.slice(0, $$i).concat($$a.slice($$i + 1))
                    );
                }
              } else {
                _vm.$set(_vm.enabled, actionKey, $$c);
              }
            },
          },
        }),
      ]);
    }),
    0
  );
}

Diff between the two:

diff --git "a/.\\stock.js" "b/.\\babel.js"
index 9a9e5b8..5d4fc7b 100644
--- "a/.\\stock.js"
+++ "b/.\\babel.js"
@@ -2,6 +2,7 @@ var render = function () {
   var _vm = this;
   var _h = _vm.$createElement;
   var _c = _vm._self._c || _h;
+
   return _c(
     'div',
     _vm._l(_vm.actionKeys, function (actionKey) {
@@ -15,33 +16,43 @@ var render = function () {
               expression: 'enabled[actionKey]',
             },
           ],
-          attrs: { type: 'checkbox' },
+          attrs: {
+            type: 'checkbox',
+          },
           domProps: {
             checked: Array.isArray(_vm.enabled[actionKey])
               ? _vm._i(_vm.enabled[actionKey], null) > -1
               : _vm.enabled[actionKey],
           },
           on: {
-            change: function ($event) {
+            change: function change($event) {
               var $$a = _vm.enabled[actionKey],
                 $$el = $event.target,
                 $$c = $$el.checked ? true : false;
+
               if (Array.isArray($$a)) {
                 var $$v = null,
                   $$i = _vm._i($$a, $$v);
+
                 if ($$el.checked) {
-                  $$i < 0 &&
-                    _vm.$set(_vm.enabled, actionKey, $$a.concat([$$v]));
+                  _vm.$$i < 0 &&
+                    _vm.$set(
+                      _vm.enabled,
+                      _vm.actionKey,
+                      _vm.$$a.concat([_vm.$$v])
+                    );
                 } else {
-                  $$i > -1 &&
+                  _vm.$$i > -1 &&
                     _vm.$set(
                       _vm.enabled,
-                      actionKey,
-                      $$a.slice(0, $$i).concat($$a.slice($$i + 1))
+                      _vm.actionKey,
+                      _vm.$$a
+                        .slice(0, _vm.$$i)
+                        .concat(_vm.$$a.slice(_vm.$$i + 1))
                     );
                 }
               } else {
-                _vm.$set(_vm.enabled, actionKey, $$c);
+                _vm.$set(_vm.enabled, _vm.actionKey, $$c);
               }
             },
           },

Usage

<template>
  <div>
    <div v-for="actionKey in actionKeys">
      <input type="checkbox" v-model="enabled[actionKey]" />
    </div>
  </div>
</template>

Extra

JuniorTour commented 2 years ago

It is a bug. Thanks for feedback.

I may look into it later. Sorry for the inconvenience.

Welcome for pull request!😊


Seems to be related to the core logic:

https://github.com/JuniorTour/vue-template-babel-compiler/blob/96bb88929e9c13cc8d408c5045bb1d984d869f2a/src/plugins/utils/shouldPrependVM.js

We need take v-for into consideration.

FedorIF commented 2 years ago

Bug is not only with indexer, also getting this problem with function params in nested scoped slots:

<app-table>
    <template #cell="{ column, row, cell }">
        <span @click="myMethod(row.id)">here is ok</span>
        <dropdown-menu>
            <template #item="{ item }">
                <span>{{ row.id }} - here is ok</span>
                <span @click="myMethod(row.id)">here is NOT ok, _vm. prepended</span>
            </template>
        </dropdown-menu>
    </template>
</app-table>
JuniorTour commented 2 years ago

@ascott18 @FedorIF

Sorry to have kept you waiting.

We just publish new version 1.0.5 , it will fix your issue.

You can try it by:

npm install vue-template-babel-compiler@1.0.5 -D
// or yarn
yarn add vue-template-babel-compiler@1.0.5 -D

Fixed DEMO for v-for && <checkbox v-model>

wecom-temp-d8b3e37fd90b7c9869e2361780573524

Fixed DEMO for nested scoped slot

wecom-temp-ad135dec948d02bcfaf981bee378d81a