Save Record Action
This commit is contained in:
parent
eaa8d91392
commit
58b5502f77
|
@ -0,0 +1,138 @@
|
||||||
|
<script>
|
||||||
|
import { Select, Label } from "@budibase/bbui"
|
||||||
|
import { store, backendUiStore } from "builderStore"
|
||||||
|
import fetchBindableProperties from "builderStore/fetchBindableProperties"
|
||||||
|
import SaveFields from "./SaveFields.svelte"
|
||||||
|
import {
|
||||||
|
readableToRuntimeBinding,
|
||||||
|
runtimeToReadableBinding,
|
||||||
|
} from "builderStore/replaceBindings"
|
||||||
|
|
||||||
|
// parameters.contextPath used in the client handler to determine which record to save
|
||||||
|
// this could be "data" or "data.parent", "data.parent.parent" etc
|
||||||
|
export let parameters
|
||||||
|
|
||||||
|
$: bindableProperties = fetchBindableProperties({
|
||||||
|
componentInstanceId: $store.currentComponentInfo._id,
|
||||||
|
components: $store.components,
|
||||||
|
screen: $store.currentPreviewItem,
|
||||||
|
models: $backendUiStore.models,
|
||||||
|
})
|
||||||
|
|
||||||
|
// we pick all the _id fields, to determine all the available
|
||||||
|
// record contexts
|
||||||
|
let idFields
|
||||||
|
|
||||||
|
const idBindingToContextPath = id => id.substring(0, id.length - 4)
|
||||||
|
const contextPathToId = path => `${path}._id`
|
||||||
|
|
||||||
|
$: {
|
||||||
|
idFields = bindableProperties.filter(
|
||||||
|
bindable =>
|
||||||
|
bindable.type === "context" && bindable.runtimeBinding.endsWith("._id")
|
||||||
|
)
|
||||||
|
// ensure contextPath is always defaulted - there is usually only one option
|
||||||
|
if (idFields.length > 0 && !parameters.contextPath) {
|
||||||
|
parameters.contextPath = idBindingToContextPath(
|
||||||
|
idFields[0].runtimeBinding
|
||||||
|
)
|
||||||
|
parameters = parameters
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// just wraps binding in {{ ... }}
|
||||||
|
const toBindingExpression = bindingPath => `{{ ${bindingPath} }}`
|
||||||
|
|
||||||
|
// finds the selected idBinding, then reads the table/view
|
||||||
|
// from the component instance that it belongs to.
|
||||||
|
// then returns the field names for that schema
|
||||||
|
const schemaFromContextPath = contextPath => {
|
||||||
|
if (!contextPath) return []
|
||||||
|
|
||||||
|
const idBinding = bindableProperties.find(
|
||||||
|
prop => prop.runtimeBinding === contextPathToId(contextPath)
|
||||||
|
)
|
||||||
|
if (!idBinding) return []
|
||||||
|
|
||||||
|
const { instance } = idBinding
|
||||||
|
|
||||||
|
const component = $store.components[instance._component]
|
||||||
|
|
||||||
|
// component.context is the name of the prop that holds the modelId
|
||||||
|
const modelInfo = instance[component.context]
|
||||||
|
const modelId =
|
||||||
|
typeof modelInfo === "string" ? modelInfo : modelInfo.modelId
|
||||||
|
|
||||||
|
if (!modelInfo) return []
|
||||||
|
|
||||||
|
const model = $backendUiStore.models.find(m => m._id === modelId)
|
||||||
|
parameters.modelId = modelId
|
||||||
|
return Object.keys(model.schema).map(k => ({
|
||||||
|
name: k,
|
||||||
|
type: model.schema[k].type,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
let schemaFields
|
||||||
|
$: {
|
||||||
|
if (parameters && parameters.contextPath) {
|
||||||
|
schemaFields = schemaFromContextPath(parameters.contextPath)
|
||||||
|
} else {
|
||||||
|
schemaFields = []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const onFieldsChanged = e => {
|
||||||
|
parameters.fields = e.detail
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="root">
|
||||||
|
{#if idFields.length === 0}
|
||||||
|
<div class="cannot-use">
|
||||||
|
Update record can only be used within a component that provides data, such
|
||||||
|
as a List
|
||||||
|
</div>
|
||||||
|
{:else}
|
||||||
|
<Label size="m" color="dark">Datasource</Label>
|
||||||
|
<Select secondary bind:value={parameters.contextPath}>
|
||||||
|
<option value="" />
|
||||||
|
{#each idFields as idField}
|
||||||
|
<option value={idBindingToContextPath(idField.runtimeBinding)}>
|
||||||
|
{idField.instance._instanceName}
|
||||||
|
</option>
|
||||||
|
{/each}
|
||||||
|
</Select>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
{#if parameters.contextPath}
|
||||||
|
<SaveFields
|
||||||
|
parameterFields={parameters.fields}
|
||||||
|
{schemaFields}
|
||||||
|
on:fieldschanged={onFieldsChanged} />
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.root {
|
||||||
|
display: grid;
|
||||||
|
column-gap: var(--spacing-s);
|
||||||
|
row-gap: var(--spacing-s);
|
||||||
|
grid-template-columns: auto 1fr auto 1fr auto;
|
||||||
|
align-items: baseline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.root :global(> div:nth-child(2)) {
|
||||||
|
grid-column-start: 2;
|
||||||
|
grid-column-end: 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cannot-use {
|
||||||
|
color: var(--red);
|
||||||
|
font-size: var(--font-size-s);
|
||||||
|
text-align: center;
|
||||||
|
width: 70%;
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -1,6 +1,5 @@
|
||||||
import NavigateTo from "./NavigateTo.svelte"
|
import NavigateTo from "./NavigateTo.svelte"
|
||||||
import UpdateRecord from "./UpdateRecord.svelte"
|
import SaveRecord from "./SaveRecord.svelte"
|
||||||
import CreateRecord from "./CreateRecord.svelte"
|
|
||||||
|
|
||||||
// defines what actions are available, when adding a new one
|
// defines what actions are available, when adding a new one
|
||||||
// the component is the setup panel for the action
|
// the component is the setup panel for the action
|
||||||
|
@ -9,15 +8,11 @@ import CreateRecord from "./CreateRecord.svelte"
|
||||||
|
|
||||||
export default [
|
export default [
|
||||||
{
|
{
|
||||||
name: "Create Record",
|
name: "Save Record",
|
||||||
component: CreateRecord,
|
component: SaveRecord,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Navigate To",
|
name: "Navigate To",
|
||||||
component: NavigateTo,
|
component: NavigateTo,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: "Update Record",
|
|
||||||
component: UpdateRecord,
|
|
||||||
},
|
|
||||||
]
|
]
|
||||||
|
|
|
@ -583,23 +583,7 @@ export default {
|
||||||
icon: "ri-file-edit-line",
|
icon: "ri-file-edit-line",
|
||||||
properties: {
|
properties: {
|
||||||
design: { ...all },
|
design: { ...all },
|
||||||
settings: [
|
settings: [],
|
||||||
{
|
|
||||||
label: "Table",
|
|
||||||
key: "model",
|
|
||||||
control: ModelSelect,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "Title",
|
|
||||||
key: "title",
|
|
||||||
control: Input,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "Button Text",
|
|
||||||
key: "buttonText",
|
|
||||||
control: Input,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -608,23 +592,7 @@ export default {
|
||||||
icon: "ri-file-edit-line",
|
icon: "ri-file-edit-line",
|
||||||
properties: {
|
properties: {
|
||||||
design: { ...all },
|
design: { ...all },
|
||||||
settings: [
|
settings: [],
|
||||||
{
|
|
||||||
label: "Table",
|
|
||||||
key: "model",
|
|
||||||
control: ModelSelect,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "Title",
|
|
||||||
key: "title",
|
|
||||||
control: Input,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "Button Text",
|
|
||||||
key: "buttonText",
|
|
||||||
control: Input,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|
|
@ -52,14 +52,14 @@ const apiOpts = {
|
||||||
delete: del,
|
delete: del,
|
||||||
}
|
}
|
||||||
|
|
||||||
const createRecord = async params =>
|
const saveRecord = async (params, state) =>
|
||||||
await post({
|
await post({
|
||||||
url: `/api/${params.modelId}/records`,
|
url: `/api/${params.modelId}/records`,
|
||||||
body: makeRecordRequestBody(params),
|
body: makeRecordRequestBody(params, state),
|
||||||
})
|
})
|
||||||
|
|
||||||
const updateRecord = async params => {
|
const updateRecord = async (params, state) => {
|
||||||
const record = makeRecordRequestBody(params)
|
const record = makeRecordRequestBody(params, state)
|
||||||
record._id = params._id
|
record._id = params._id
|
||||||
await patch({
|
await patch({
|
||||||
url: `/api/${params.modelId}/records/${params._id}`,
|
url: `/api/${params.modelId}/records/${params._id}`,
|
||||||
|
@ -67,8 +67,14 @@ const updateRecord = async params => {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const makeRecordRequestBody = parameters => {
|
const makeRecordRequestBody = (parameters, state) => {
|
||||||
const body = {}
|
// start with the record thats currently in context
|
||||||
|
const body = { ...(state.data || {}) }
|
||||||
|
|
||||||
|
// dont send the model
|
||||||
|
if (body._model) delete body._model
|
||||||
|
|
||||||
|
// then override with supplied parameters
|
||||||
for (let fieldName in parameters.fields) {
|
for (let fieldName in parameters.fields) {
|
||||||
const field = parameters.fields[fieldName]
|
const field = parameters.fields[fieldName]
|
||||||
|
|
||||||
|
@ -95,6 +101,6 @@ const makeRecordRequestBody = parameters => {
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
authenticate: authenticate(apiOpts),
|
authenticate: authenticate(apiOpts),
|
||||||
createRecord,
|
saveRecord,
|
||||||
updateRecord,
|
updateRecord,
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,8 +6,8 @@ export const EVENT_TYPE_MEMBER_NAME = "##eventHandlerType"
|
||||||
export const eventHandlers = routeTo => {
|
export const eventHandlers = routeTo => {
|
||||||
const handlers = {
|
const handlers = {
|
||||||
"Navigate To": param => routeTo(param && param.url),
|
"Navigate To": param => routeTo(param && param.url),
|
||||||
"Create Record": api.createRecord,
|
|
||||||
"Update Record": api.updateRecord,
|
"Update Record": api.updateRecord,
|
||||||
|
"Save Record": api.saveRecord,
|
||||||
"Trigger Workflow": api.triggerWorkflow,
|
"Trigger Workflow": api.triggerWorkflow,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ export const eventHandlers = routeTo => {
|
||||||
const handler = handlers[action[EVENT_TYPE_MEMBER_NAME]]
|
const handler = handlers[action[EVENT_TYPE_MEMBER_NAME]]
|
||||||
const parameters = createParameters(action.parameters, state)
|
const parameters = createParameters(action.parameters, state)
|
||||||
if (handler) {
|
if (handler) {
|
||||||
await handler(parameters)
|
await handler(parameters, state)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -95,7 +95,7 @@ const getState = contextStoreKey =>
|
||||||
contextStoreKey ? contextStores[contextStoreKey].state : rootState
|
contextStoreKey ? contextStores[contextStoreKey].state : rootState
|
||||||
|
|
||||||
const getStore = contextStoreKey =>
|
const getStore = contextStoreKey =>
|
||||||
contextStoreKey ? contextStores[contextStoreKey] : rootStore
|
contextStoreKey ? contextStores[contextStoreKey].store : rootStore
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
subscribe,
|
subscribe,
|
||||||
|
|
|
@ -218,20 +218,12 @@
|
||||||
"dataform": {
|
"dataform": {
|
||||||
"description": "an HTML table that fetches data from a table or view and displays it.",
|
"description": "an HTML table that fetches data from a table or view and displays it.",
|
||||||
"data": true,
|
"data": true,
|
||||||
"props": {
|
"props": {}
|
||||||
"model": "models",
|
|
||||||
"title": "string",
|
|
||||||
"buttonText": "string"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"dataformwide": {
|
"dataformwide": {
|
||||||
"description": "an HTML table that fetches data from a table or view and displays it.",
|
"description": "an HTML table that fetches data from a table or view and displays it.",
|
||||||
"data": true,
|
"data": true,
|
||||||
"props": {
|
"props": {}
|
||||||
"model": "models",
|
|
||||||
"title": "string",
|
|
||||||
"buttonText": "string"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"datalist": {
|
"datalist": {
|
||||||
"description": "A configurable data list that attaches to your backend models.",
|
"description": "A configurable data list that attaches to your backend models.",
|
||||||
|
|
|
@ -1,168 +1,61 @@
|
||||||
<script>
|
<script>
|
||||||
import { onMount } from "svelte"
|
import { Label, DatePicker, Input, Select, Toggle } from "@budibase/bbui"
|
||||||
import { fade } from "svelte/transition"
|
|
||||||
import {
|
|
||||||
Label,
|
|
||||||
DatePicker,
|
|
||||||
Input,
|
|
||||||
Select,
|
|
||||||
Button,
|
|
||||||
Toggle,
|
|
||||||
} from "@budibase/bbui"
|
|
||||||
import Dropzone from "./attachments/Dropzone.svelte"
|
import Dropzone from "./attachments/Dropzone.svelte"
|
||||||
import LinkedRecordSelector from "./LinkedRecordSelector.svelte"
|
import LinkedRecordSelector from "./LinkedRecordSelector.svelte"
|
||||||
import debounce from "lodash.debounce"
|
|
||||||
import ErrorsBox from "./ErrorsBox.svelte"
|
import ErrorsBox from "./ErrorsBox.svelte"
|
||||||
import { capitalise } from "./helpers"
|
import { capitalise } from "./helpers"
|
||||||
|
|
||||||
export let _bb
|
export let _bb
|
||||||
export let model
|
export let model
|
||||||
export let title
|
|
||||||
export let buttonText
|
|
||||||
export let wide = false
|
export let wide = false
|
||||||
|
|
||||||
const TYPE_MAP = {
|
|
||||||
string: "text",
|
|
||||||
boolean: "checkbox",
|
|
||||||
number: "number",
|
|
||||||
}
|
|
||||||
|
|
||||||
const DEFAULTS_FOR_TYPE = {
|
|
||||||
string: "",
|
|
||||||
boolean: false,
|
|
||||||
number: null,
|
|
||||||
link: [],
|
|
||||||
}
|
|
||||||
|
|
||||||
let record
|
|
||||||
let store = _bb.store
|
let store = _bb.store
|
||||||
let schema = {}
|
let schema = {}
|
||||||
let modelDef = {}
|
|
||||||
let saved = false
|
|
||||||
let recordId
|
let recordId
|
||||||
let isNew = true
|
|
||||||
let errors = {}
|
let errors = {}
|
||||||
|
|
||||||
|
$: schema = $store.data && $store.data._model.schema
|
||||||
$: fields = schema ? Object.keys(schema) : []
|
$: fields = schema ? Object.keys(schema) : []
|
||||||
$: if (model && model.length !== 0) {
|
|
||||||
fetchModel()
|
|
||||||
}
|
|
||||||
|
|
||||||
async function fetchModel() {
|
|
||||||
const FETCH_MODEL_URL = `/api/models/${model}`
|
|
||||||
const response = await _bb.api.get(FETCH_MODEL_URL)
|
|
||||||
modelDef = await response.json()
|
|
||||||
schema = modelDef.schema
|
|
||||||
record = {
|
|
||||||
modelId: model,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const save = debounce(async () => {
|
|
||||||
for (let field of fields) {
|
|
||||||
// Assign defaults to empty fields to prevent validation issues
|
|
||||||
if (!(field in record)) {
|
|
||||||
record[field] = DEFAULTS_FOR_TYPE[schema[field].type]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const SAVE_RECORD_URL = `/api/${model}/records`
|
|
||||||
const response = await _bb.api.post(SAVE_RECORD_URL, record)
|
|
||||||
|
|
||||||
const json = await response.json()
|
|
||||||
|
|
||||||
if (response.status === 200) {
|
|
||||||
store.update(state => {
|
|
||||||
state[model] = state[model] ? [...state[model], json] : [json]
|
|
||||||
return state
|
|
||||||
})
|
|
||||||
|
|
||||||
errors = {}
|
|
||||||
|
|
||||||
// wipe form, if new record, otherwise update
|
|
||||||
// model to get new _rev
|
|
||||||
record = isNew ? { modelId: model } : json
|
|
||||||
|
|
||||||
// set saved, and unset after 1 second
|
|
||||||
// i.e. make the success notifier appear, then disappear again after time
|
|
||||||
saved = true
|
|
||||||
setTimeout(() => {
|
|
||||||
saved = false
|
|
||||||
}, 3000)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (response.status === 400) {
|
|
||||||
errors = Object.keys(json.errors)
|
|
||||||
.map(k => ({ dataPath: k, message: json.errors[k] }))
|
|
||||||
.flat()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
onMount(async () => {
|
|
||||||
const routeParams = _bb.routeParams()
|
|
||||||
recordId =
|
|
||||||
Object.keys(routeParams).length > 0 && (routeParams.id || routeParams[0])
|
|
||||||
isNew = !recordId || recordId === "new"
|
|
||||||
|
|
||||||
if (isNew) {
|
|
||||||
record = { modelId: model }
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const GET_RECORD_URL = `/api/${model}/records/${recordId}`
|
|
||||||
const response = await _bb.api.get(GET_RECORD_URL)
|
|
||||||
record = await response.json()
|
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<form class="form" on:submit|preventDefault>
|
<div class="form-content">
|
||||||
{#if title}
|
<ErrorsBox errors={$store.saveRecordErrors || {}} />
|
||||||
<h1>{title}</h1>
|
{#each fields as field}
|
||||||
{/if}
|
<div class="form-field" class:wide>
|
||||||
<div class="form-content">
|
{#if !(schema[field].type === 'boolean' && !wide)}
|
||||||
<ErrorsBox {errors} />
|
<Label extraSmall={!wide} grey={!wide}>
|
||||||
{#each fields as field}
|
{capitalise(schema[field].name)}
|
||||||
<div class="form-field" class:wide>
|
</Label>
|
||||||
{#if !(schema[field].type === 'boolean' && !wide)}
|
{/if}
|
||||||
<Label extraSmall={!wide} grey={!wide}>
|
{#if schema[field].type === 'options'}
|
||||||
{capitalise(schema[field].name)}
|
<Select secondary bind:value={$store.data[field]}>
|
||||||
</Label>
|
<option value="">Choose an option</option>
|
||||||
{/if}
|
{#each schema[field].constraints.inclusion as opt}
|
||||||
{#if schema[field].type === 'options'}
|
<option>{opt}</option>
|
||||||
<Select secondary bind:value={record[field]}>
|
{/each}
|
||||||
<option value="">Choose an option</option>
|
</Select>
|
||||||
{#each schema[field].constraints.inclusion as opt}
|
{:else if schema[field].type === 'datetime'}
|
||||||
<option>{opt}</option>
|
<DatePicker bind:value={$store.data[field]} />
|
||||||
{/each}
|
{:else if schema[field].type === 'boolean'}
|
||||||
</Select>
|
<Toggle
|
||||||
{:else if schema[field].type === 'datetime'}
|
text={wide ? null : capitalise(schema[field].name)}
|
||||||
<DatePicker bind:value={record[field]} />
|
bind:checked={$store.data[field]} />
|
||||||
{:else if schema[field].type === 'boolean'}
|
{:else if schema[field].type === 'number'}
|
||||||
<Toggle
|
<Input type="number" bind:value={$store.data[field]} />
|
||||||
text={wide ? null : capitalise(schema[field].name)}
|
{:else if schema[field].type === 'string'}
|
||||||
bind:checked={record[field]} />
|
<Input bind:value={$store.data[field]} />
|
||||||
{:else if schema[field].type === 'number'}
|
{:else if schema[field].type === 'attachment'}
|
||||||
<Input type="number" bind:value={record[field]} />
|
<Dropzone bind:files={$store.data[field]} />
|
||||||
{:else if schema[field].type === 'string'}
|
{:else if schema[field].type === 'link'}
|
||||||
<Input bind:value={record[field]} />
|
<LinkedRecordSelector
|
||||||
{:else if schema[field].type === 'attachment'}
|
secondary
|
||||||
<Dropzone bind:files={record[field]} />
|
showLabel={false}
|
||||||
{:else if schema[field].type === 'link'}
|
bind:linkedRecords={$store.data[field]}
|
||||||
<LinkedRecordSelector
|
schema={schema[field]} />
|
||||||
secondary
|
{/if}
|
||||||
showLabel={false}
|
|
||||||
bind:linkedRecords={record[field]}
|
|
||||||
schema={schema[field]} />
|
|
||||||
{/if}
|
|
||||||
</div>
|
|
||||||
{/each}
|
|
||||||
<div class="buttons">
|
|
||||||
<Button primary on:click={save} green={saved}>
|
|
||||||
{#if saved}Success{:else}{buttonText || 'Submit Form'}{/if}
|
|
||||||
</Button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
{/each}
|
||||||
</form>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.form {
|
.form {
|
||||||
|
@ -189,9 +82,4 @@
|
||||||
.form-field.wide :global(label) {
|
.form-field.wide :global(label) {
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.buttons {
|
|
||||||
display: flex;
|
|
||||||
justify-content: flex-end;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
<script>
|
<script>
|
||||||
import { onMount } from "svelte"
|
import { onMount } from "svelte"
|
||||||
import { isEmpty } from "lodash/fp"
|
|
||||||
|
|
||||||
export let _bb
|
export let _bb
|
||||||
export let model
|
export let model
|
||||||
|
@ -13,8 +12,17 @@
|
||||||
|
|
||||||
let target
|
let target
|
||||||
|
|
||||||
|
async function fetchModel(id) {
|
||||||
|
const FETCH_MODEL_URL = `/api/models/${id}`
|
||||||
|
const response = await _bb.api.get(FETCH_MODEL_URL)
|
||||||
|
return await response.json()
|
||||||
|
}
|
||||||
|
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
if (!isEmpty(record) && record.model) {
|
if (model) {
|
||||||
|
const modelObj = await fetchModel(modelId)
|
||||||
|
record.modelId = model
|
||||||
|
record._model = modelObj
|
||||||
_bb.attachChildren(target, {
|
_bb.attachChildren(target, {
|
||||||
context: record,
|
context: record,
|
||||||
})
|
})
|
||||||
|
|
|
@ -51,6 +51,8 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
record._model = model
|
||||||
|
|
||||||
_bb.attachChildren(target, {
|
_bb.attachChildren(target, {
|
||||||
context: record,
|
context: record,
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in New Issue