Bladeren bron

feat: Update lifecycle and mutation (#4000)

* feat: Update lifecycle and mutation

The goal is to support "add reorder" that happen in the same mutation.

* add test for _x_isInit
Alexandre Lepretre 1 jaar geleden
bovenliggende
commit
4c2397ca1c
3 gewijzigde bestanden met toevoegingen van 43 en 8 verwijderingen
  1. 13 7
      packages/alpinejs/src/lifecycle.js
  2. 0 1
      packages/alpinejs/src/mutation.js
  3. 30 0
      tests/cypress/integration/mutation.spec.js

+ 13 - 7
packages/alpinejs/src/lifecycle.js

@@ -81,13 +81,18 @@ export function interceptInit(callback) { initInterceptors.push(callback) }
 export function initTree(el, walker = walk, intercept = () => {}) {
     deferHandlingDirectives(() => {
         walker(el, (el, skip) => {
-            intercept(el, skip)
-
-            initInterceptors.forEach(i => i(el, skip))
-
-            directives(el, el.attributes).forEach(handle => handle())
-
-            el._x_ignore && skip()
+            if (!el._x_isInit) {
+                intercept(el, skip)
+
+                initInterceptors.forEach(i => i(el, skip))
+                directives(el, el.attributes).forEach(handle => handle())
+            }
+
+            if (el._x_ignore) {
+                skip()
+            } else {
+                el._x_isInit = true
+            }
         })
     })
 }
@@ -96,5 +101,6 @@ export function destroyTree(root) {
     walk(root, el => {
         cleanupAttributes(el)
         cleanupElement(el)
+        delete el._x_isInit
     })
 }

+ 0 - 1
packages/alpinejs/src/mutation.js

@@ -196,7 +196,6 @@ function onMutate(mutations) {
     for (let node of addedNodes) {
         // If the node was eventually removed as part of one of his
         // parent mutations, skip it
-        if (removedNodes.has(node)) continue
         if (! node.isConnected) continue
 
         delete node._x_ignoreSelf

+ 30 - 0
tests/cypress/integration/mutation.spec.js

@@ -136,6 +136,36 @@ test('can pause and queue mutations for later resuming/flushing',
     }
 )
 
+test('add and move element are been initialized',
+    html`
+        <div x-data="{
+            foo: 0,
+            bar: 0,
+            test() {
+                container = document.createElement('div')
+                this.$root.appendChild(container)
+                alpineElement = document.createElement('span')
+                alpineElement.setAttribute('x-data', '{init() {this.bar++}}')
+                alpineElement.setAttribute('x-init', 'foo++')
+                container.appendChild(alpineElement)
+                container.removeChild(alpineElement)
+                container.appendChild(alpineElement)
+            }
+        }">
+            <span id="one" x-text="foo"></span>
+            <span id="two" x-text="bar"></span>
+            <button @click="test">Test</button>
+        </div>
+    `,
+    ({ get }) => {
+        get('span#one').should(haveText('0'))
+        get('span#two').should(haveText('0'))
+        get('button').click()
+        get('span#one').should(haveText('1'))
+        get('span#two').should(haveText('1'))
+    }
+)
+
 test('does not initialise components twice when contained in multiple mutations',
     html`
         <div x-data="{