diff --git a/packages/client/src/components/ClientApp.svelte b/packages/client/src/components/ClientApp.svelte
index a0be2120b5..f4af80ab83 100644
--- a/packages/client/src/components/ClientApp.svelte
+++ b/packages/client/src/components/ClientApp.svelte
@@ -2,11 +2,11 @@
import { setContext, onMount } from "svelte"
import Component from "./Component.svelte"
import SDK from "../sdk"
- import { routeStore, screenStore, createDataContextStore } from "../store"
+ import { routeStore, screenStore, createDataStore } from "../store"
// Provide contexts
setContext("sdk", SDK)
- setContext("data", createDataContextStore())
+ setContext("data", createDataStore())
let loaded = false
diff --git a/packages/client/src/components/Component.svelte b/packages/client/src/components/Component.svelte
index b17dd0d7d2..f003033f08 100644
--- a/packages/client/src/components/Component.svelte
+++ b/packages/client/src/components/Component.svelte
@@ -3,6 +3,8 @@
import { writable } from "svelte/store"
import * as ComponentLibrary from "@budibase/standard-components"
import Router from "./Router.svelte"
+ import { enrichDataBinding } from "../utils"
+ import { bindingStore } from "../store"
export let definition = {}
@@ -23,6 +25,19 @@
return props
}
+ // Enriches data bindings to real values based on data context
+ const enrichDataBindings = (data, bindings, props) => {
+ const state = {
+ ...data,
+ ...bindings,
+ }
+ let enrichedProps = {}
+ Object.entries(props).forEach(([key, value]) => {
+ enrichedProps[key] = enrichDataBinding(value, state)
+ })
+ return enrichedProps
+ }
+
// Gets the component constructor for the specified component
const getComponentConstructor = name => {
return name === "screenslot" ? Router : ComponentLibrary[componentName]
@@ -32,14 +47,25 @@
$: componentName = extractComponentName(definition._component)
$: constructor = getComponentConstructor(componentName)
$: componentProps = extractValidProps(definition)
- $: dataContext = getContext("data")
- $: enrichedProps = dataContext.actions.enrichDataBindings(componentProps)
$: children = definition._children
+ $: id = definition._id
+ $: dataStore = getContext("data")
+ $: enrichedProps = enrichDataBindings(
+ $dataStore,
+ $bindingStore,
+ componentProps
+ )
- // Set observable style context
- const styleStore = writable({})
- setContext("style", styleStore)
- $: styleStore.set({ ...definition._styles, id: definition._id })
+ // Update component context
+ // ID is duplicated inside style so that the "styleable" helper can set
+ // an ID data tag for unique reference to components
+ const componentStore = writable({})
+ setContext("component", componentStore)
+ $: componentStore.set({
+ id,
+ styles: { ...definition._styles, id },
+ dataContext: $dataStore.data,
+ })
{#if constructor}
diff --git a/packages/client/src/components/DataProvider.svelte b/packages/client/src/components/DataProvider.svelte
index 08defe93b6..4ee04d722c 100644
--- a/packages/client/src/components/DataProvider.svelte
+++ b/packages/client/src/components/DataProvider.svelte
@@ -1,19 +1,19 @@
diff --git a/packages/client/src/components/Router.svelte b/packages/client/src/components/Router.svelte
index 4921e65c87..0f89924b66 100644
--- a/packages/client/src/components/Router.svelte
+++ b/packages/client/src/components/Router.svelte
@@ -5,7 +5,7 @@
import Screen from "./Screen.svelte"
const { styleable } = getContext("sdk")
- const styles = getContext("style")
+ const component = getContext("component")
$: routerConfig = getRouterConfig($routeStore.routes)
@@ -26,7 +26,7 @@
{#if routerConfig}
-
+
{/if}
diff --git a/packages/client/src/sdk.js b/packages/client/src/sdk.js
index cad3e20bd5..3a5a3f80ac 100644
--- a/packages/client/src/sdk.js
+++ b/packages/client/src/sdk.js
@@ -1,5 +1,5 @@
import * as API from "./api"
-import { authStore, routeStore, screenStore } from "./store"
+import { authStore, routeStore, screenStore, bindingStore } from "./store"
import { styleable, getAppId } from "./utils"
import { link as linkable } from "svelte-spa-router"
import DataProvider from "./components/DataProvider.svelte"
@@ -13,4 +13,5 @@ export default {
linkable,
getAppId,
DataProvider,
+ setBindableValue: bindingStore.actions.setBindableValue,
}
diff --git a/packages/client/src/store/auth.js b/packages/client/src/store/auth.js
index 54ee35e8da..ac616e9240 100644
--- a/packages/client/src/store/auth.js
+++ b/packages/client/src/store/auth.js
@@ -5,9 +5,6 @@ import { writable } from "svelte/store"
const createAuthStore = () => {
const store = writable("")
- /**
- * Logs a user in.
- */
const logIn = async ({ username, password }) => {
const user = await API.logIn({ username, password })
if (!user.error) {
@@ -15,10 +12,6 @@ const createAuthStore = () => {
location.reload()
}
}
-
- /**
- * Logs a user out.
- */
const logOut = () => {
store.set("")
const appId = getAppId()
diff --git a/packages/client/src/store/binding.js b/packages/client/src/store/binding.js
new file mode 100644
index 0000000000..b279142c32
--- /dev/null
+++ b/packages/client/src/store/binding.js
@@ -0,0 +1,21 @@
+import { writable } from "svelte/store"
+
+const createBindingStore = () => {
+ const store = writable({})
+
+ const setBindableValue = (value, componentId) => {
+ store.update(state => {
+ if (componentId) {
+ state[componentId] = value
+ }
+ return state
+ })
+ }
+
+ return {
+ subscribe: store.subscribe,
+ actions: { setBindableValue },
+ }
+}
+
+export const bindingStore = createBindingStore()
diff --git a/packages/client/src/store/data.js b/packages/client/src/store/data.js
new file mode 100644
index 0000000000..9cd44eebb4
--- /dev/null
+++ b/packages/client/src/store/data.js
@@ -0,0 +1,27 @@
+import { writable } from "svelte/store"
+import { cloneDeep } from "lodash/fp"
+
+const initialValue = {
+ data: null,
+}
+
+export const createDataStore = existingContext => {
+ const initial = existingContext ? cloneDeep(existingContext) : initialValue
+ const store = writable(initial)
+
+ // Adds a context layer to the data context tree
+ const addContext = (row, componentId) => {
+ store.update(state => {
+ if (componentId) {
+ state[componentId] = row
+ state.data = row
+ }
+ return state
+ })
+ }
+
+ return {
+ subscribe: store.subscribe,
+ actions: { addContext },
+ }
+}
diff --git a/packages/client/src/store/dataContext.js b/packages/client/src/store/dataContext.js
deleted file mode 100644
index 90acc42664..0000000000
--- a/packages/client/src/store/dataContext.js
+++ /dev/null
@@ -1,39 +0,0 @@
-import { writable, get } from "svelte/store"
-import { enrichDataBinding } from "../utils"
-import { cloneDeep } from "lodash/fp"
-
-const initialValue = {
- data: null,
-}
-
-export const createDataContextStore = existingContext => {
- const initial = existingContext ? cloneDeep(existingContext) : initialValue
- const store = writable(initial)
-
- // Adds a context layer to the data context tree
- const addContext = (row, componentId) => {
- store.update(state => {
- if (row && componentId) {
- state[componentId] = row
- state.data = row
- }
- return state
- })
- }
-
- // Enriches props by running mustache and filling in any data bindings present
- // in the prop values
- const enrichDataBindings = props => {
- const state = get(store)
- let enrichedProps = {}
- Object.entries(props).forEach(([key, value]) => {
- enrichedProps[key] = enrichDataBinding(value, state)
- })
- return enrichedProps
- }
-
- return {
- subscribe: store.subscribe,
- actions: { addContext, enrichDataBindings },
- }
-}
diff --git a/packages/client/src/store/index.js b/packages/client/src/store/index.js
index 4416ca809a..3730f39ee0 100644
--- a/packages/client/src/store/index.js
+++ b/packages/client/src/store/index.js
@@ -1,5 +1,8 @@
export { authStore } from "./auth"
export { routeStore } from "./routes"
export { screenStore } from "./screens"
-export { createDataContextStore } from "./dataContext"
export { builderStore } from "./builder"
+export { bindingStore } from "./binding"
+
+// Data stores are layered and duplicated, so it is not a singleton
+export { createDataStore } from "./data"
diff --git a/packages/standard-components/src/Button.svelte b/packages/standard-components/src/Button.svelte
index 6dbbcfc4cf..1d64c5e8bd 100644
--- a/packages/standard-components/src/Button.svelte
+++ b/packages/standard-components/src/Button.svelte
@@ -2,14 +2,17 @@
import { getContext } from "svelte"
const { styleable } = getContext("sdk")
- const styles = getContext("style")
+ const component = getContext("component")
export let className = "default"
export let disabled = false
export let text
-