Form component now supports edit recprd

This commit is contained in:
Michael Shanks 2020-07-07 20:16:03 +01:00
parent 6a4ac519aa
commit 208f5b33c1
5 changed files with 113 additions and 22 deletions

View File

@ -1,5 +1,5 @@
import regexparam from "regexparam" import regexparam from "regexparam"
import { routerStore } from "../state/store" import { appStore } from "../state/store"
import { getAppId } from "./getAppId" import { getAppId } from "./getAppId"
export const screenRouter = ({ screens, onScreenSelected, window }) => { export const screenRouter = ({ screens, onScreenSelected, window }) => {
@ -49,7 +49,7 @@ export const screenRouter = ({ screens, onScreenSelected, window }) => {
}) })
} }
routerStore.update(state => { appStore.update(state => {
state["##routeParams"] = params state["##routeParams"] = params
return state return state
}) })

View File

@ -8,6 +8,7 @@ export const bbFactory = ({
store, store,
componentLibraries, componentLibraries,
onScreenSlotRendered, onScreenSlotRendered,
getCurrentState,
}) => { }) => {
const apiCall = method => (url, body) => { const apiCall = method => (url, body) => {
return fetch(url, { return fetch(url, {
@ -53,6 +54,8 @@ export const bbFactory = ({
store: store, store: store,
api, api,
parent, parent,
// these parameters are populated by screenRouter
routeParams: () => getCurrentState()["##routeParams"],
} }
} }
} }

View File

@ -26,8 +26,14 @@ export const createStateManager = ({
routeTo, routeTo,
}) => { }) => {
let handlerTypes = eventHandlers(routeTo) let handlerTypes = eventHandlers(routeTo)
let currentState
// creating a reference to the current state
// this avoids doing store.get() ... which is expensive on
// hot paths, according to the svelte docs.
// the state object reference never changes (although it's internals do)
// so this should work fine for us
let currentState
appStore.subscribe(s => (currentState = s))
const getCurrentState = () => currentState const getCurrentState = () => currentState
const bb = bbFactory({ const bb = bbFactory({

View File

@ -13,14 +13,14 @@
number: "number", number: "number",
} }
let newModel = { let record
modelId: model,
}
let store = _bb.store let store = _bb.store
let schema = {} let schema = {}
let modelDef = {} let modelDef = {}
let saved = false let saved = false
let saving = false let saving = false
let recordId
let isNew = true
let inputElements = {} let inputElements = {}
@ -30,6 +30,8 @@
$: fields = Object.keys(schema) $: fields = Object.keys(schema)
$: Object.values(inputElements).length && setForm(record)
async function fetchModel() { async function fetchModel() {
const FETCH_MODEL_URL = `/api/models/${model}` const FETCH_MODEL_URL = `/api/models/${model}`
const response = await _bb.api.get(FETCH_MODEL_URL) const response = await _bb.api.get(FETCH_MODEL_URL)
@ -42,7 +44,8 @@
if (saving) return if (saving) return
saving = true saving = true
const SAVE_RECORD_URL = `/api/${model}/records` const SAVE_RECORD_URL = `/api/${model}/records`
const response = await _bb.api.post(SAVE_RECORD_URL, newModel) const response = await _bb.api.post(SAVE_RECORD_URL, record)
const json = await response.json() const json = await response.json()
if (response.status === 200) { if (response.status === 200) {
@ -51,7 +54,13 @@
return state return state
}) })
resetForm() // wipe form, if new record, otherwise update
// model to get new _rev
if (isNew) {
resetForm()
} else {
record = json
}
// set saved, and unset after 1 second // set saved, and unset after 1 second
// i.e. make the success notifier appear, then disappear again after time // i.e. make the success notifier appear, then disappear again after time
@ -72,29 +81,58 @@
el.checked = false el.checked = false
} }
} }
newModel = { record = {
modelId: model modelId: model
} }
} }
const setForm = rec => {
if (isNew || !rec) return
for (let fieldName in inputElements) {
if (typeof rec[fieldName] === "boolean") {
inputElements[fieldName].checked = rec[fieldName]
} else {
inputElements[fieldName].value = rec[fieldName]
}
}
}
const handleInput = field => event => { const handleInput = field => event => {
let value let value
if (event.target.type === "checkbox") { if (event.target.type === "checkbox") {
value = event.target.checked value = event.target.checked
newModel[field] = value record[field] = value
return return
} }
if (event.target.type === "number") { if (event.target.type === "number") {
value = parseInt(event.target.value) value = parseInt(event.target.value)
newModel[field] = value record[field] = value
return return
} }
value = event.target.value value = event.target.value
newModel[field] = value record[field] = value
} }
onMount(() => {
const routeParams = _bb.routeParams()
recordId = Object.keys(routeParams).length > 0 && (routeParams.id || routeParams[0])
isNew = !recordId || recordId === "new"
if (isNew) {
record = { modelId: model }
} else {
const GET_RECORD_URL = `/api/${model}/records/${recordId}`
_bb.api.get(GET_RECORD_URL)
.then(response => response.json())
.then(rec => {
record = rec
setForm(rec)
})
}
});
</script> </script>
<form class="form" on:submit|preventDefault> <form class="form" on:submit|preventDefault>

View File

@ -13,33 +13,39 @@
number: "number", number: "number",
} }
let newModel = { let record
modelId: model,
}
let store = _bb.store let store = _bb.store
let schema = {} let schema = {}
let modelDef = {} let modelDef = {}
let saved = false let saved = false
let saving = false let saving = false
let recordId
let isNew = true
let inputElements = {} let inputElements = {}
$: if (model && model.length !== 0) { $: if (model && model.length !== 0) {
fetchModel() fetchModel()
} }
$: fields = Object.keys(schema) $: fields = Object.keys(schema)
$: Object.values(inputElements).length && setForm(record)
async function fetchModel() { async function fetchModel() {
const FETCH_MODEL_URL = `/api/models/${model}` const FETCH_MODEL_URL = `/api/models/${model}`
const response = await _bb.api.get(FETCH_MODEL_URL) const response = await _bb.api.get(FETCH_MODEL_URL)
modelDef = await response.json() modelDef = await response.json()
schema = modelDef.schema schema = modelDef.schema
} }
async function save() { async function save() {
// prevent double clicking firing multiple requests // prevent double clicking firing multiple requests
if (saving) return if (saving) return
saving = true saving = true
const SAVE_RECORD_URL = `/api/${model}/records` const SAVE_RECORD_URL = `/api/${model}/records`
const response = await _bb.api.post(SAVE_RECORD_URL, newModel) const response = await _bb.api.post(SAVE_RECORD_URL, record)
const json = await response.json() const json = await response.json()
if (response.status === 200) { if (response.status === 200) {
@ -48,7 +54,13 @@
return state return state
}) })
resetForm() // wipe form, if new record, otherwise update
// model to get new _rev
if (isNew) {
resetForm()
} else {
record = json
}
// set saved, and unset after 1 second // set saved, and unset after 1 second
// i.e. make the success notifier appear, then disappear again after time // i.e. make the success notifier appear, then disappear again after time
@ -69,26 +81,58 @@
el.checked = false el.checked = false
} }
} }
newModel = { record = {
modelId: model modelId: model
} }
} }
const setForm = rec => {
if (isNew || !rec) return
for (let fieldName in inputElements) {
if (typeof rec[fieldName] === "boolean") {
inputElements[fieldName].checked = rec[fieldName]
} else {
inputElements[fieldName].value = rec[fieldName]
}
}
}
const handleInput = field => event => { const handleInput = field => event => {
let value let value
if (event.target.type === "checkbox") { if (event.target.type === "checkbox") {
value = event.target.checked value = event.target.checked
newModel[field] = value record[field] = value
return return
} }
if (event.target.type === "number") { if (event.target.type === "number") {
value = parseInt(event.target.value) value = parseInt(event.target.value)
newModel[field] = value record[field] = value
return return
} }
value = event.target.value value = event.target.value
newModel[field] = value record[field] = value
} }
onMount(() => {
const routeParams = _bb.routeParams()
recordId = Object.keys(routeParams).length > 0 && (routeParams.id || routeParams[0])
isNew = !recordId || recordId === "new"
if (isNew) {
record = { modelId: model }
} else {
const GET_RECORD_URL = `/api/${model}/records/${recordId}`
_bb.api.get(GET_RECORD_URL)
.then(response => response.json())
.then(rec => {
record = rec
setForm(rec)
})
}
});
</script> </script>
<form class="form" on:submit|preventDefault> <form class="form" on:submit|preventDefault>
@ -127,7 +171,7 @@
{buttonText || "Submit Form"} {buttonText || "Submit Form"}
</div> </div>
{/if} {/if}
</button> </button>
</div> </div>
</div> </div>
</form> </form>