Selaa lähdekoodia

Merge pull request #418 from SimoTod/feature/x-for-bindings

Fix x-on in x-for when updating
Caleb Porzio 5 vuotta sitten
vanhempi
commit
c116279bf6
4 muutettua tiedostoa jossa 48 lisäystä ja 33 poistoa
  1. 6 11
      dist/alpine-ie11.js
  2. 6 11
      dist/alpine.js
  3. 7 11
      src/directives/for.js
  4. 29 0
      test/for.spec.js

+ 6 - 11
dist/alpine-ie11.js

@@ -5801,9 +5801,9 @@
 
       var iterationScopeVariables = getIterationScopeVariables(iteratorNames, item, index, items, extraVars());
       var currentKey = generateKeyForIteration(component, templateEl, index, iterationScopeVariables);
-      var nextEl = currentEl.nextElementSibling; // If there's no previously x-for processed element ahead, add one.
+      var nextEl = lookAheadForMatchingKeyedElementAndMoveItIfFound(currentEl.nextElementSibling, currentKey); // If we haven't found a matching key, insert the element at the current position.
 
-      if (!nextEl || nextEl.__x_for_key === undefined) {
+      if (!nextEl) {
         nextEl = addElementInLoopAfterCurrentEl(templateEl, currentEl); // And transition it in if it's not the first page load.
 
         transitionIn(nextEl, function () {
@@ -5814,15 +5814,9 @@
           _newArrowCheck(this, _this2);
 
           return nextEl.__x_for;
-        }.bind(this));
+        }.bind(this)); // Otherwise update the element we found.
       } else {
-        nextEl = lookAheadForMatchingKeyedElementAndMoveItIfFound(nextEl, currentKey); // If we haven't found a matching key, just insert the element at the current position
-
-        if (!nextEl) {
-          nextEl = addElementInLoopAfterCurrentEl(templateEl, currentEl);
-        } // Temporarily remove the key indicator to allow the normal "updateElements" to work
-
-
+        // Temporarily remove the key indicator to allow the normal "updateElements" to work.
         delete nextEl.__x_for_key;
         nextEl.__x_for = iterationScopeVariables;
         component.updateElements(nextEl, function () {
@@ -5911,7 +5905,8 @@
   }
 
   function lookAheadForMatchingKeyedElementAndMoveItIfFound(nextEl, currentKey) {
-    // If the the key's DO match, no need to look ahead.
+    if (!nextEl) return; // If the the key's DO match, no need to look ahead.
+
     if (nextEl.__x_for_key === currentKey) return nextEl; // If they don't, we'll look ahead for a match.
     // If we find it, we'll move it to the current position in the loop.
 

+ 6 - 11
dist/alpine.js

@@ -396,22 +396,16 @@
     items.forEach((item, index) => {
       let iterationScopeVariables = getIterationScopeVariables(iteratorNames, item, index, items, extraVars());
       let currentKey = generateKeyForIteration(component, templateEl, index, iterationScopeVariables);
-      let nextEl = currentEl.nextElementSibling; // If there's no previously x-for processed element ahead, add one.
+      let nextEl = lookAheadForMatchingKeyedElementAndMoveItIfFound(currentEl.nextElementSibling, currentKey); // If we haven't found a matching key, insert the element at the current position.
 
-      if (!nextEl || nextEl.__x_for_key === undefined) {
+      if (!nextEl) {
         nextEl = addElementInLoopAfterCurrentEl(templateEl, currentEl); // And transition it in if it's not the first page load.
 
         transitionIn(nextEl, () => {}, initialUpdate);
         nextEl.__x_for = iterationScopeVariables;
-        component.initializeElements(nextEl, () => nextEl.__x_for);
+        component.initializeElements(nextEl, () => nextEl.__x_for); // Otherwise update the element we found.
       } else {
-        nextEl = lookAheadForMatchingKeyedElementAndMoveItIfFound(nextEl, currentKey); // If we haven't found a matching key, just insert the element at the current position
-
-        if (!nextEl) {
-          nextEl = addElementInLoopAfterCurrentEl(templateEl, currentEl);
-        } // Temporarily remove the key indicator to allow the normal "updateElements" to work
-
-
+        // Temporarily remove the key indicator to allow the normal "updateElements" to work.
         delete nextEl.__x_for_key;
         nextEl.__x_for = iterationScopeVariables;
         component.updateElements(nextEl, () => nextEl.__x_for);
@@ -486,7 +480,8 @@
   }
 
   function lookAheadForMatchingKeyedElementAndMoveItIfFound(nextEl, currentKey) {
-    // If the the key's DO match, no need to look ahead.
+    if (!nextEl) return; // If the the key's DO match, no need to look ahead.
+
     if (nextEl.__x_for_key === currentKey) return nextEl; // If they don't, we'll look ahead for a match.
     // If we find it, we'll move it to the current position in the loop.
 

+ 7 - 11
src/directives/for.js

@@ -12,10 +12,10 @@ export function handleForDirective(component, templateEl, expression, initialUpd
     items.forEach((item, index) => {
         let iterationScopeVariables = getIterationScopeVariables(iteratorNames, item, index, items, extraVars())
         let currentKey = generateKeyForIteration(component, templateEl, index, iterationScopeVariables)
-        let nextEl = currentEl.nextElementSibling
+        let nextEl = lookAheadForMatchingKeyedElementAndMoveItIfFound(currentEl.nextElementSibling, currentKey)
 
-        // If there's no previously x-for processed element ahead, add one.
-        if (! nextEl || nextEl.__x_for_key === undefined) {
+        // If we haven't found a matching key, insert the element at the current position.
+        if (! nextEl) {
             nextEl = addElementInLoopAfterCurrentEl(templateEl, currentEl)
 
             // And transition it in if it's not the first page load.
@@ -23,15 +23,9 @@ export function handleForDirective(component, templateEl, expression, initialUpd
 
             nextEl.__x_for = iterationScopeVariables
             component.initializeElements(nextEl, () => nextEl.__x_for)
+        // Otherwise update the element we found.
         } else {
-            nextEl = lookAheadForMatchingKeyedElementAndMoveItIfFound(nextEl, currentKey)
-
-            // If we haven't found a matching key, just insert the element at the current position
-            if (! nextEl) {
-                nextEl = addElementInLoopAfterCurrentEl(templateEl, currentEl)
-            }
-
-            // Temporarily remove the key indicator to allow the normal "updateElements" to work
+            // Temporarily remove the key indicator to allow the normal "updateElements" to work.
             delete nextEl.__x_for_key
 
             nextEl.__x_for = iterationScopeVariables
@@ -114,6 +108,8 @@ function addElementInLoopAfterCurrentEl(templateEl, currentEl) {
 }
 
 function lookAheadForMatchingKeyedElementAndMoveItIfFound(nextEl, currentKey) {
+    if (! nextEl) return
+
     // If the the key's DO match, no need to look ahead.
     if (nextEl.__x_for_key === currentKey) return nextEl
 

+ 29 - 0
test/for.spec.js

@@ -448,3 +448,32 @@ test('nested x-for event listeners', async () => {
         expect(document._alerts[2]).toEqual('foo: bob = 2')
     })
 })
+
+test('make sure new elements with different keys added to the beginning of a loop are initialized instead of just updated', async () => {
+    let clickCount = 0
+    window.registerClick = () => {
+        clickCount++
+    }
+
+    document.body.innerHTML = `
+        <div x-data="{ items: ['foo'] }">
+            <button @click="items = ['bar']">Change</button>
+
+            <template x-for="item in items" :key="item">
+                <h1 @click="registerClick()"></h1>
+            </template>
+        </div>
+    `
+
+    Alpine.start()
+
+    document.querySelector('h1').click()
+
+    expect(clickCount).toEqual(1)
+
+    document.querySelector('button').click()
+
+    document.querySelector('h1').click()
+
+    expect(clickCount).toEqual(2)
+})