Parcourir la source

Fix nested x-for loop scoping

Caleb Porzio il y a 5 ans
Parent
commit
67970f2cb7
6 fichiers modifiés avec 59 ajouts et 9 suppressions
  1. 3 3
      dist/alpine-ie11.js
  2. 3 3
      dist/alpine.js
  3. 19 0
      examples/index.html
  4. 1 1
      src/component.js
  5. 2 2
      src/directives/for.js
  6. 31 0
      test/for.spec.js

+ 3 - 3
dist/alpine-ie11.js

@@ -5349,7 +5349,7 @@
     return !isNaN(subject);
   }
 
-  function handleForDirective(component, el, expression, initialUpdate) {
+  function handleForDirective(component, el, expression, initialUpdate, extraVars) {
     var _this = this;
 
     if (el.tagName.toLowerCase() !== 'template') console.warn('Alpine: [x-for] directive should only be added to <template> tags.');
@@ -5369,7 +5369,7 @@
       // empty, effectively hiding it.
       items = [];
     } else {
-      items = component.evaluateReturnExpression(el, bunch);
+      items = component.evaluateReturnExpression(el, bunch, extraVars);
     } // As we walk the array, we'll also walk the DOM (updating/creating as we go).
 
 
@@ -6410,7 +6410,7 @@
               break;
 
             case 'for':
-              handleForDirective(this, el, expression, initialUpdate);
+              handleForDirective(this, el, expression, initialUpdate, extraVars);
               break;
 
             case 'cloak':

+ 3 - 3
dist/alpine.js

@@ -395,7 +395,7 @@
     return !isNaN(subject);
   }
 
-  function handleForDirective(component, el, expression, initialUpdate) {
+  function handleForDirective(component, el, expression, initialUpdate, extraVars) {
     if (el.tagName.toLowerCase() !== 'template') console.warn('Alpine: [x-for] directive should only be added to <template> tags.');
     const {
       single,
@@ -412,7 +412,7 @@
       // empty, effectively hiding it.
       items = [];
     } else {
-      items = component.evaluateReturnExpression(el, bunch);
+      items = component.evaluateReturnExpression(el, bunch, extraVars);
     } // As we walk the array, we'll also walk the DOM (updating/creating as we go).
 
 
@@ -1501,7 +1501,7 @@
             break;
 
           case 'for':
-            handleForDirective(this, el, expression, initialUpdate);
+            handleForDirective(this, el, expression, initialUpdate, extraVars);
             break;
 
           case 'cloak':

+ 19 - 0
examples/index.html

@@ -246,6 +246,25 @@
                     </td>
                 </tr>
 
+                <tr>
+                    <td>Nested x-for</td>
+                    <td>
+                        <div x-data="{ foos: [{bars: [{bobs: ['one', 'two']}, {bobs: ['three', 'four']}]}, {bars: [{bobs: ['five', 'six']}, {bobs: ['seven', 'eight']}]}] }">
+                            <template x-for="foo in foos">
+                                <div>
+                                    <template x-for="bar in foo.bars">
+                                        <div>
+                                            <template x-for="bob in bar.bobs">
+                                                <span x-text="bob"></span>
+                                            </template>
+                                        </div>
+                                    </template>
+                                </div>
+                            </template>
+                        </div>
+                    </td>
+                </tr>
+
                 <tr>
                     <td>Transitions</td>
                     <td>

+ 1 - 1
src/component.js

@@ -275,7 +275,7 @@ export default class Component {
                     break;
 
                 case 'for':
-                    handleForDirective(this, el, expression, initialUpdate)
+                    handleForDirective(this, el, expression, initialUpdate, extraVars)
                     break;
 
                 case 'cloak':

+ 2 - 2
src/directives/for.js

@@ -1,6 +1,6 @@
 import { transitionIn, transitionOut, getXAttrs } from '../utils'
 
-export function handleForDirective(component, el, expression, initialUpdate) {
+export function handleForDirective(component, el, expression, initialUpdate, extraVars) {
     if (el.tagName.toLowerCase() !== 'template') console.warn('Alpine: [x-for] directive should only be added to <template> tags.')
 
     const { single, bunch, iterator1, iterator2 } = parseFor(expression)
@@ -13,7 +13,7 @@ export function handleForDirective(component, el, expression, initialUpdate) {
         // empty, effectively hiding it.
         items = []
     } else {
-        items = component.evaluateReturnExpression(el, bunch)
+        items = component.evaluateReturnExpression(el, bunch, extraVars)
     }
 
     // As we walk the array, we'll also walk the DOM (updating/creating as we go).

+ 31 - 0
test/for.spec.js

@@ -288,3 +288,34 @@ test('listeners in loop get fresh iteration data even though they are only regis
 
     await wait(() => { expect(document.querySelector('h1').innerText).toEqual('bar') })
 })
+
+test('nested x-for', async () => {
+    document.body.innerHTML = `
+        <div x-data="{ foos: [ {bars: ['bob', 'lob']} ] }">
+            <button x-on:click="foos = [ {bars: ['bob', 'lob']}, {bars: ['law']} ]"></button>
+            <template x-for="foo in foos">
+                <h1>
+                    <template x-for="bar in foo.bars">
+                        <h2 x-text="bar"></h2>
+                    </template>
+                </h1>
+            </template>
+        </div>
+    `
+
+    Alpine.start()
+
+    await wait(() => { expect(document.querySelectorAll('h1').length).toEqual(1) })
+    await wait(() => { expect(document.querySelectorAll('h2').length).toEqual(2) })
+
+    expect(document.querySelectorAll('h2')[0].innerText).toEqual('bob')
+    expect(document.querySelectorAll('h2')[1].innerText).toEqual('lob')
+
+    document.querySelector('button').click()
+
+    await wait(() => { expect(document.querySelectorAll('h2').length).toEqual(3) })
+
+    expect(document.querySelectorAll('h2')[0].innerText).toEqual('bob')
+    expect(document.querySelectorAll('h2')[1].innerText).toEqual('lob')
+    expect(document.querySelectorAll('h2')[2].innerText).toEqual('law')
+})