Преглед на файлове

Allow access to parent scope from within getters and setters

Caleb Porzio преди 3 години
родител
ревизия
31671b411f
променени са 2 файла, в които са добавени 41 реда и са изтрити 2 реда
  1. 26 2
      packages/alpinejs/src/scope.js
  2. 15 0
      tests/cypress/integration/directives/x-data.spec.js

+ 26 - 2
packages/alpinejs/src/scope.js

@@ -42,7 +42,7 @@ export function closestDataProxy(el) {
 }
 
 export function mergeProxies(objects) {
-    return new Proxy({}, {
+    let thisProxy = new Proxy({}, {
         ownKeys: () => {
             return Array.from(new Set(objects.flatMap(i => Object.keys(i))))
         },
@@ -52,7 +52,29 @@ export function mergeProxies(objects) {
         },
 
         get: (target, name) => {
-            return (objects.find(obj => obj.hasOwnProperty(name)) || {})[name]
+            return (objects.find(obj => {
+                if (obj.hasOwnProperty(name)) {
+                    let descriptor = Object.getOwnPropertyDescriptor(obj, name)
+                    
+                    // Properly bind getters and setters to this wrapper Proxy.
+                    if ((descriptor.get || descriptor.set) && descriptor.enumerable) {
+                        // Only bind user-defined getters, not our magic properties.
+                        let getter = descriptor.get
+                        let setter = descriptor.set
+                        let property = descriptor
+
+                        Object.defineProperty(obj, name, {
+                            ...property,
+                            get: getter && getter.bind(thisProxy),
+                            set: setter && setter.bind(thisProxy),
+                        })
+                    }
+
+                    return true 
+                }
+
+                return false
+            }) || {})[name]
         },
 
         set: (target, name, value) => {
@@ -67,4 +89,6 @@ export function mergeProxies(objects) {
             return true
         },
     })
+
+    return thisProxy
 }

+ 15 - 0
tests/cypress/integration/directives/x-data.spec.js

@@ -109,3 +109,18 @@ test('x-data works on the html tag',
         get('span').should(haveText('foo'))
     }
 )
+
+test('x-data getters have access to parent scope',
+    html`
+    <div x-data="{ foo: 'bar' }">
+        <div x-data="{
+            get bob() {
+                return this.foo
+            }
+        }">
+            <h1 x-text="bob"></h1>
+        </div>
+    </div>
+    `,
+    ({ get }) => get('h1').should(haveText('bar'))
+)