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 { setStyles } from './utils/styles'
 import { debounce } from './utils/debounce'
 import { debounce } from './utils/debounce'
 import { throttle } from './utils/throttle'
 import { throttle } from './utils/throttle'
+import { mergeProxies } from './scope'
 import { nextTick } from './nextTick'
 import { nextTick } from './nextTick'
 import { plugin } from './plugin'
 import { plugin } from './plugin'
 import { magic } from './magics'
 import { magic } from './magics'
@@ -29,6 +30,7 @@ let Alpine = {
     mapAttributes,
     mapAttributes,
     evaluateLater,
     evaluateLater,
     setEvaluator,
     setEvaluator,
+    mergeProxies,
     closestRoot,
     closestRoot,
     interceptor, // INTERNAL: not public API and is subject to change without major release.
     interceptor, // INTERNAL: not public API and is subject to change without major release.
     transition, // INTERNAL
     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 './$dispatch'
 import './$watch'
 import './$watch'
 import './$store'
 import './$store'
+import './$data'
 import './$root'
 import './$root'
 import './$refs'
 import './$refs'
 import './$el'
 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
 title: dispatch
 ---
 ---
 
 
-# `$dispatch`
+# $dispatch
 
 
 `$dispatch` is a helpful shortcut for dispatching browser events.
 `$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
 title: el
 ---
 ---
 
 
-# `$el`
+# $el
 
 
 `$el` is a magic property that can be used to retrieve the current DOM node.
 `$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
 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.
 `$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
 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`.
 `$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
 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`.
 `$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
 title: store
 ---
 ---
 
 
-# `$store`
+# $store
 
 
 You can use `$store` to conveniently access global Alpine stores registered using [`Alpine.store(...)`](#). For example:
 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
 title: watch
 ---
 ---
 
 
-# `$watch`
+# $watch
 
 
 You can "watch" a component property using the `$watch` magic method. For example:
 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'))
+    }
+)