Form: success notifier on save + configurable button text

This commit is contained in:
Michael Shanks 2020-07-06 16:24:44 +01:00
parent 8bc5cf564b
commit a55865e34c
4 changed files with 122 additions and 14 deletions

View File

@ -350,6 +350,11 @@ export default {
key: "title",
control: Input,
},
{
label: "Button Text",
key: "buttonText",
control: Input,
},
],
},
template: {
@ -375,6 +380,11 @@ export default {
key: "title",
control: Input,
},
{
label: "Button Text",
key: "buttonText",
control: Input,
},
],
},
},

View File

@ -208,7 +208,8 @@
"data": true,
"props": {
"model": "models",
"title": "string"
"title": "string",
"buttonText": "string"
}
},
"dataformwide": {
@ -216,7 +217,8 @@
"data": true,
"props": {
"model": "models",
"title": "string"
"title": "string",
"buttonText": "string"
}
},
"datalist": {

View File

@ -1,9 +1,11 @@
<script>
import { onMount } from "svelte"
import { fade } from "svelte/transition"
export let _bb
export let model
export let title
export let buttonText
const TYPE_MAP = {
string: "text",
@ -17,6 +19,10 @@
let store = _bb.store
let schema = {}
let modelDef = {}
let saved = false
let saving = false
let inputElements = {}
$: if (model && model.length !== 0) {
fetchModel()
@ -32,14 +38,39 @@
}
async function save() {
// prevent double clicking firing multiple requests
if (saving) return
saving = true
const SAVE_RECORD_URL = `/api/${model}/records`
const response = await _bb.api.post(SAVE_RECORD_URL, newModel)
const json = await response.json()
store.update(state => {
state[model] = state[model] ? [...state[model], json] : [json]
return state
})
if (response.status === 200) {
store.update(state => {
state[model] = state[model] ? [...state[model], json] : [json]
return state
})
resetForm()
saved = true
setTimeout(() => {
saved = false
}, 1000)
}
saving = false
}
const resetForm = () => {
for (let el of Object.values(inputElements)) {
el.value = ""
if (el.checked) {
el.checked = false
}
}
newModel = {
modelId: model
}
}
const handleInput = field => event => {
@ -72,13 +103,14 @@
<div class="form-item">
<label class="form-label" for="form-stacked-text">{field}</label>
{#if schema[field].type === 'string' && schema[field].constraints.inclusion}
<select on:blur={handleInput(field)}>
<select on:blur={handleInput(field)} bind:this={inputElements[field]}>
{#each schema[field].constraints.inclusion as opt}
<option>{opt}</option>
{/each}
</select>
{:else}
<input
bind:this={inputElements[field]}
class="input"
type={TYPE_MAP[schema[field].type]}
on:change={handleInput(field)} />
@ -87,7 +119,17 @@
<hr />
{/each}
<div class="button-block">
<button on:click={save}>Submit Form</button>
<button on:click={save} class:saved>
{#if saved}
<div in:fade>
<span class:saved style="margin-right: 5px">🎉</span>Success<span class:saved style="margin-left: 5px">🎉</span>
</div>
{:else}
<div>
{buttonText || "Submit Form"}
</div>
{/if}
</button>
</div>
</div>
</form>
@ -157,6 +199,10 @@
text-align: center;
}
button.saved {
background-color: green;
}
button:hover {
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1),
0 4px 6px -2px rgba(0, 0, 0, 0.05);

View File

@ -1,8 +1,11 @@
<script>
import { onMount } from "svelte"
import { fade } from "svelte/transition"
export let _bb
export let model
export let title
export let buttonText
const TYPE_MAP = {
string: "text",
@ -16,6 +19,11 @@
let store = _bb.store
let schema = {}
let modelDef = {}
let saved = false
let saving = false
let inputElements = {}
$: if (model && model.length !== 0) {
fetchModel()
}
@ -27,14 +35,41 @@
schema = modelDef.schema
}
async function save() {
// prevent double clicking firing multiple requests
if (saving) return
saving = true
const SAVE_RECORD_URL = `/api/${model}/records`
const response = await _bb.api.post(SAVE_RECORD_URL, newModel)
const json = await response.json()
store.update(state => {
state[model] = state[model] ? [...state[model], json] : [json]
return state
})
if (response.status === 200) {
store.update(state => {
state[model] = state[model] ? [...state[model], json] : [json]
return state
})
resetForm()
saved = true
setTimeout(() => {
saved = false
}, 1000)
}
saving = false
}
const resetForm = () => {
for (let el of Object.values(inputElements)) {
el.value = ""
if (el.checked) {
el.checked = false
}
}
newModel = {
modelId: model
}
}
const handleInput = field => event => {
let value
if (event.target.type === "checkbox") {
@ -62,13 +97,14 @@
<div class="form-item">
<label class="form-label" for="form-stacked-text">{field}</label>
{#if schema[field].type === 'string' && schema[field].constraints.inclusion}
<select on:blur={handleInput(field)}>
<select on:blur={handleInput(field)} bind:this={inputElements[field]}>
{#each schema[field].constraints.inclusion as opt}
<option>{opt}</option>
{/each}
</select>
{:else}
<input
bind:this={inputElements[field]}
class="input"
type={TYPE_MAP[schema[field].type]}
on:change={handleInput(field)} />
@ -77,7 +113,17 @@
<hr />
{/each}
<div class="button-block">
<button on:click={save}>Submit Form</button>
<button on:click={save} class:saved>
{#if saved}
<div in:fade>
<span class:saved style="margin-right: 5px">🎉</span>Success<span class:saved style="margin-left: 5px">🎉</span>
</div>
{:else}
<div>
{buttonText || "Submit Form"}
</div>
{/if}
</button>
</div>
</div>
</form>
@ -138,6 +184,10 @@
text-align: center;
}
button.saved {
background-color: green;
}
button:hover {
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1),
0 4px 6px -2px rgba(0, 0, 0, 0.05);