Kaynağa Gözat

Bug: init() function doesn't have access to the parent scope (#1874)

* Add failing test

* Fix bug that prevented init() from accessing the parent scope
Simone Todaro 3 yıl önce
ebeveyn
işleme
39c55e1bd4

+ 2 - 2
packages/alpinejs/src/directives/x-data.js

@@ -29,11 +29,11 @@ directive('data', skipDuringClone((el, { expression }, { cleanup }) => {
 
     let undo = addScopeToNode(el, reactiveData)
 
-    if (reactiveData['init']) reactiveData['init']()
+    reactiveData['init'] && evaluate(el, reactiveData['init'])
 
     cleanup(() => {
         undo()
 
-        reactiveData['destroy'] && reactiveData['destroy']()
+        reactiveData['destroy'] && evaluate(el, reactiveData['destroy'])
     })
 }))

+ 51 - 0
tests/cypress/integration/custom-data.spec.js

@@ -115,3 +115,54 @@ test('init functions "this" context is reactive',
         get('span').should(haveText('baz'))
     }
 )
+
+test('init functions have access to the parent scope',
+    html`
+        <script>
+            document.addEventListener('alpine:init', () => {
+                Alpine.data('parent', () => ({
+                    foo: 'bar',
+                }))
+
+                Alpine.data('child', () => ({
+                    init() {
+                        this.$el.textContent = this.foo
+                    },
+                }))
+            })
+        </script>
+
+        <div x-data="parent">
+            <p x-data="child"></p>
+        </div>
+    `,
+    ({ get }) => {
+        get('p').should(haveText('bar'))
+    }
+)
+
+test('destroy functions inside custom datas are called automatically',
+    html`
+        <script>
+            document.addEventListener('alpine:init', () => {
+                Alpine.data('test', () => ({
+                    destroy() {
+                        document.querySelector('span').textContent = 'foo'
+                    },
+                    test() {
+                        Alpine.closestRoot(this.$el).remove()
+                    }
+                }))
+            })
+        </script>
+
+        <div x-data="test">
+            <button x-on:click="test()"></button>
+        </div>
+        <span><span>
+    `,
+    ({ get }) => {
+        get('button').click()
+        get('span').should(haveText('foo'))
+    }
+)