Tidy up data binding

This commit is contained in:
Andrew Kingston 2020-11-20 10:49:39 +00:00
parent a6821814f8
commit 911fa31fe3
6 changed files with 19 additions and 51 deletions

View File

@ -24,7 +24,7 @@ import { cloneDeep, difference } from "lodash/fp"
* @returns {Array.<BindableProperty>} * @returns {Array.<BindableProperty>}
*/ */
export default function({ componentInstanceId, screen, components, tables }) { export default function({ componentInstanceId, screen, components, tables }) {
const walkResult = walk({ const result = walk({
// cloning so we are free to mutate props (e.g. by adding _contexts) // cloning so we are free to mutate props (e.g. by adding _contexts)
instance: cloneDeep(screen.props), instance: cloneDeep(screen.props),
targetId: componentInstanceId, targetId: componentInstanceId,
@ -33,13 +33,10 @@ export default function({ componentInstanceId, screen, components, tables }) {
}) })
return [ return [
...walkResult.bindableInstances ...result.bindableInstances
.filter(isInstanceInSharedContext(walkResult)) .filter(isInstanceInSharedContext(result))
.map(componentInstanceToBindable(walkResult)), .map(componentInstanceToBindable),
...(result.target?._contexts.map(contextToBindables(tables)).flat() ?? []),
...(walkResult.target?._contexts
.map(contextToBindables(tables, walkResult))
.flat() ?? []),
] ]
} }
@ -53,26 +50,18 @@ const isInstanceInSharedContext = walkResult => i =>
// turns a component instance prop into binding expressions // turns a component instance prop into binding expressions
// used by the UI // used by the UI
const componentInstanceToBindable = walkResult => i => { const componentInstanceToBindable = i => {
const lastContext =
i.instance._contexts.length &&
i.instance._contexts[i.instance._contexts.length - 1]
const contextParentPath = lastContext
? getParentPath(walkResult, lastContext)
: ""
return { return {
type: "instance", type: "instance",
instance: i.instance, instance: i.instance,
// how the binding expression persists, and is used in the app at runtime // how the binding expression persists, and is used in the app at runtime
runtimeBinding: `${contextParentPath}${i.instance._id}.${i.prop}`, runtimeBinding: `${i.instance._id}`,
// how the binding exressions looks to the user of the builder // how the binding exressions looks to the user of the builder
readableBinding: `${i.instance._instanceName}`, readableBinding: `${i.instance._instanceName}`,
} }
} }
const contextToBindables = (tables, walkResult) => context => { const contextToBindables = tables => context => {
const contextParentPath = getParentPath(walkResult, context)
const tableId = context.table?.tableId ?? context.table const tableId = context.table?.tableId ?? context.table
const table = tables.find(table => table._id === tableId) const table = tables.find(table => table._id === tableId)
let schema = let schema =
@ -98,7 +87,7 @@ const contextToBindables = (tables, walkResult) => context => {
fieldSchema, fieldSchema,
instance: context.instance, instance: context.instance,
// how the binding expression persists, and is used in the app at runtime // how the binding expression persists, and is used in the app at runtime
runtimeBinding: `${contextParentPath}data.${runtimeBoundKey}`, runtimeBinding: `${context.instance._id}.${runtimeBoundKey}`,
// how the binding expressions looks to the user of the builder // how the binding expressions looks to the user of the builder
readableBinding: `${context.instance._instanceName}.${table.name}.${key}`, readableBinding: `${context.instance._instanceName}.${table.name}.${key}`,
// table / view info // table / view info
@ -118,20 +107,6 @@ const contextToBindables = (tables, walkResult) => context => {
) )
} }
const getParentPath = (walkResult, context) => {
// describes the number of "parent" in the path
// clone array first so original array is not mtated
const contextParentNumber = [...walkResult.target._contexts]
.reverse()
.indexOf(context)
return (
new Array(contextParentNumber).fill("parent").join(".") +
// trailing . if has parents
(contextParentNumber ? "." : "")
)
}
const walk = ({ instance, targetId, components, tables, result }) => { const walk = ({ instance, targetId, components, tables, result }) => {
if (!result) { if (!result) {
result = { result = {

View File

@ -12,10 +12,7 @@ export function readableToRuntimeBinding(bindableProperties, textWithBindings) {
return boundValue === `{{ ${readableBinding} }}` return boundValue === `{{ ${readableBinding} }}`
}) })
if (binding) { if (binding) {
result = textWithBindings.replace( result = result.replace(boundValue, `{{ ${binding.runtimeBinding} }}`)
boundValue,
`{{ ${binding.runtimeBinding} }}`
)
} }
}) })
return result return result

View File

@ -46,7 +46,7 @@ export default `<html>
selectedComponentStyle = document.createElement('style'); selectedComponentStyle = document.createElement('style');
document.head.appendChild(selectedComponentStyle) document.head.appendChild(selectedComponentStyle)
var selectedCss = '[data-bb-id="' + data.selectedComponentType + '-' + data.selectedComponentId + '"]' + '{border:2px solid #0055ff !important;}' var selectedCss = '[data-bb-id="' + data.selectedComponentId + '"]' + '{border:2px solid #0055ff !important;}'
selectedComponentStyle.appendChild(document.createTextNode(selectedCss)) selectedComponentStyle.appendChild(document.createTextNode(selectedCss))
styles = document.createElement('style') styles = document.createElement('style')

View File

@ -30,14 +30,13 @@
// Extract component definition info // Extract component definition info
const componentName = extractComponentName(definition._component) const componentName = extractComponentName(definition._component)
const constructor = getComponentConstructor(componentName) const constructor = getComponentConstructor(componentName)
const id = `${componentName}-${definition._id}`
const componentProps = extractValidProps(definition) const componentProps = extractValidProps(definition)
const dataContext = getContext("data") const dataContext = getContext("data")
const enrichedProps = dataContext.actions.enrichDataBindings(componentProps) const enrichedProps = dataContext.actions.enrichDataBindings(componentProps)
const children = definition._children const children = definition._children
// Set style context to be consumed by component // Set contexts to be consumed by component
setContext("style", { ...definition._styles, id }) setContext("style", { ...definition._styles, id: definition._id })
$: console.log("Rendering: " + componentName) $: console.log("Rendering: " + componentName)
</script> </script>

View File

@ -6,6 +6,7 @@
// Get current contexts // Get current contexts
const dataContext = getContext("data") const dataContext = getContext("data")
const { id } = getContext("style")
// Clone current context to this context // Clone current context to this context
const newDataContext = createDataContextStore($dataContext) const newDataContext = createDataContextStore($dataContext)
@ -14,7 +15,7 @@
// Add additional layer to context // Add additional layer to context
let loaded = false let loaded = false
onMount(() => { onMount(() => {
newDataContext.actions.addContext(row) newDataContext.actions.addContext(row, id)
loaded = true loaded = true
}) })
</script> </script>

View File

@ -3,7 +3,6 @@ import { enrichDataBinding } from "../utils"
import { cloneDeep } from "lodash/fp" import { cloneDeep } from "lodash/fp"
const initialValue = { const initialValue = {
parent: null,
data: null, data: null,
} }
@ -12,15 +11,12 @@ export const createDataContextStore = existingContext => {
const store = writable(initial) const store = writable(initial)
// Adds a context layer to the data context tree // Adds a context layer to the data context tree
const addContext = row => { const addContext = (row, componentId) => {
store.update(state => { store.update(state => {
if (state.data) { if (row && componentId) {
state.parent = { state[componentId] = row
parent: state.parent, state.data = row
data: state.data,
}
} }
state.data = row
return state return state
}) })
} }