Browse Source

Add $data magic property (#2301)

Caleb Porzio 3 years ago
parent
commit
542e9f3a23

+ 2 - 0
packages/alpinejs/src/alpine.js

@@ -8,6 +8,7 @@ import { interceptor } from './interceptor'
 import { setStyles } from './utils/styles'
 import { debounce } from './utils/debounce'
 import { throttle } from './utils/throttle'
+import { mergeProxies } from './scope'
 import { nextTick } from './nextTick'
 import { plugin } from './plugin'
 import { magic } from './magics'
@@ -29,6 +30,7 @@ let Alpine = {
     mapAttributes,
     evaluateLater,
     setEvaluator,
+    mergeProxies,
     closestRoot,
     interceptor, // INTERNAL: not public API and is subject to change without major release.
     transition, // INTERNAL

+ 6 - 0
packages/alpinejs/src/magics/$data.js

@@ -0,0 +1,6 @@
+import { closestDataStack, mergeProxies } from '../scope'
+import { magic } from '../magics'
+
+magic('data', el => {
+    return mergeProxies(closestDataStack(el))
+})

+ 1 - 0
packages/alpinejs/src/magics/index.js

@@ -2,6 +2,7 @@ import './$nextTick'
 import './$dispatch'
 import './$watch'
 import './$store'
+import './$data'
 import './$root'
 import './$refs'
 import './$el'

+ 45 - 0
packages/docs/src/en/magics/data.md

@@ -0,0 +1,45 @@
+---
+order: 8
+prefix: $
+title: data
+---
+
+# $data
+
+`$data` is a magic property that gives you access to the current Alpine data scope (generally provided by `x-data`).
+
+Most of the time, you can just access Alpine data within expressions directly. for example `x-data="{ message: 'Hello Caleb!' }"` will allow you to do things like `x-text="message"`.
+
+However, sometimes it is helpful to have an actual object that encapsulates all scope that you can pass around to other functions:
+
+```alpine
+<div x-data="{ greeting: 'Hello' }">
+    <div x-data="{ name: 'Caleb' }">
+        <button @click="sayHello($data)">Say Hello</button>
+    </div>
+</div>
+
+<script>
+    function sayHello({ greeting, name }) {
+        alert(greeting + ' ' + name + '!')
+    }
+</script>
+```
+
+<!-- START_VERBATIM -->
+<div x-data="{ greeting: 'Hello' }" class="demo">
+    <div x-data="{ name: 'Caleb' }">
+        <button @click="sayHello($data)">Say Hello</button>
+    </div>
+</div>
+
+<script>
+    function sayHello({ greeting, name }) {
+        alert(greeting + ' ' + name + '!')
+    }
+</script>
+<!-- END_VERBATIM -->
+
+Now when the button is pressed, the browser will alert `Hello Caleb!` because it was passed a data object that contained all the Alpine scope of the expression that called it (`@click="..."`).
+
+Most applications won't need this magic property, but it can be very helpful for deeper, more complicated Alpine utilities.

+ 1 - 1
packages/docs/src/en/magics/dispatch.md

@@ -3,7 +3,7 @@ order: 5
 title: dispatch
 ---
 
-# `$dispatch`
+# $dispatch
 
 `$dispatch` is a helpful shortcut for dispatching browser events.
 

+ 1 - 1
packages/docs/src/en/magics/el.md

@@ -4,7 +4,7 @@ prefix: $
 title: el
 ---
 
-# `$el`
+# $el
 
 `$el` is a magic property that can be used to retrieve the current DOM node.
 

+ 1 - 1
packages/docs/src/en/magics/nextTick.md

@@ -4,7 +4,7 @@ prefix: $
 title: nextTick
 ---
 
-# `$nextTick`
+# $nextTick
 
 `$nextTick` is a magic property that allows you to only execute a given expression AFTER Alpine has made its reactive DOM updates. This is useful for times you want to interact with the DOM state AFTER it's reflected any data updates you've made.
 

+ 1 - 1
packages/docs/src/en/magics/refs.md

@@ -4,7 +4,7 @@ prefix: $
 title: refs
 ---
 
-# `$refs`
+# $refs
 
 `$refs` is a magic property that can be used to retrieve DOM elements marked with `x-ref` inside the component. This is useful when you need to manually manipulate DOM elements. It's often used as a more succinct, scoped, alternative to `document.querySelector`.
 

+ 1 - 1
packages/docs/src/en/magics/root.md

@@ -4,7 +4,7 @@ prefix: $
 title: root
 ---
 
-# `$root`
+# $root
 
 `$root` is a magic property that can be used to retrieve the root element of any Alpine component. In other words the closest element up the DOM tree that contains `x-data`.
 

+ 1 - 1
packages/docs/src/en/magics/store.md

@@ -4,7 +4,7 @@ prefix: $
 title: store
 ---
 
-# `$store`
+# $store
 
 You can use `$store` to conveniently access global Alpine stores registered using [`Alpine.store(...)`](#). For example:
 

+ 1 - 1
packages/docs/src/en/magics/watch.md

@@ -3,7 +3,7 @@ order: 4
 title: watch
 ---
 
-# `$watch`
+# $watch
 
 You can "watch" a component property using the `$watch` magic method. For example:
 

+ 14 - 0
tests/cypress/integration/magics/$data.spec.js

@@ -0,0 +1,14 @@
+import { haveText, html, test } from '../../utils'
+
+test('$data returns the current scope (with cascading)',
+    html`
+        <div x-data="{ foo: 'bar'}">
+            <div x-data="{ bob: 'lob' }">
+                <span x-text="$data.foo + ' ' + $data.bob"></span>
+            </div>
+        </div>
+    `,
+    ({ get }) => {
+        get('span').should(haveText('bar lob'))
+    }
+)