Add validation to forms
Fix values being treated as strings
This commit is contained in:
parent
e42f3656a9
commit
cea4f35d52
3 changed files with 64 additions and 38 deletions
|
@ -11,14 +11,16 @@
|
||||||
</div>
|
</div>
|
||||||
{#if showAddDialog}
|
{#if showAddDialog}
|
||||||
<div class="dialog">
|
<div class="dialog">
|
||||||
<div class="dialog-content">
|
<form class="dialog-content" novalidate bind:this={ dialogForm }>
|
||||||
<label>Name<input type="text" bind:value={newCounter.title} use:focus/></label>
|
<label>Counter Name<input type="text" required bind:value={newCounter.title} use:focus/></label>
|
||||||
<label>Initial Value<input type="text" inputmode="decimal" bind:value={newCounter.initialValue} /></label>
|
<label>Initial Value<input type="text" required pattern="(0|([1-9]\d*))(\.\d+)?" inputmode="decimal" bind:value={newCounter.initialValue} /></label>
|
||||||
<label>Target<input type="text" inputmode="decimal" bind:value={newCounter.max} /></label>
|
<label>Target<input type="text" pattern="(0|([1-9]\d*))(\.\d+)?" inputmode="decimal" bind:value={newCounter.max} /></label>
|
||||||
<label>Save history<input type="checkbox" bind:checked={newCounter.saveHistory} /></label>
|
<label>Save history<input type="checkbox" bind:checked={newCounter.saveHistory} /></label>
|
||||||
<button on:click={ () => { showAddDialog = false; } }>Cancel</button>
|
<div class="buttons">
|
||||||
<button class="ok" on:click={ add }>OK</button>
|
<button class="ok" on:click|preventDefault={ add }>OK</button>
|
||||||
|
<button on:click|preventDefault={ () => { showAddDialog = false; } }>Cancel</button>
|
||||||
</div>
|
</div>
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
{#if showAbout}
|
{#if showAbout}
|
||||||
|
@ -32,6 +34,7 @@ import { counters } from './db.js';
|
||||||
let showAddDialog = false;
|
let showAddDialog = false;
|
||||||
let showAbout = false;
|
let showAbout = false;
|
||||||
let newCounter = null;
|
let newCounter = null;
|
||||||
|
let dialogForm = null;
|
||||||
|
|
||||||
function focus(node){
|
function focus(node){
|
||||||
node.focus();
|
node.focus();
|
||||||
|
@ -41,6 +44,7 @@ function showAdd(){
|
||||||
newCounter = {
|
newCounter = {
|
||||||
title: '',
|
title: '',
|
||||||
initialValue: 0,
|
initialValue: 0,
|
||||||
|
max: '',
|
||||||
saveHistory: false,
|
saveHistory: false,
|
||||||
history: []
|
history: []
|
||||||
}
|
}
|
||||||
|
@ -49,9 +53,15 @@ function showAdd(){
|
||||||
}
|
}
|
||||||
|
|
||||||
function add(){
|
function add(){
|
||||||
|
if(!dialogForm.checkValidity()) {
|
||||||
|
dialogForm.removeAttribute('novalidate');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const counter = {
|
const counter = {
|
||||||
...newCounter,
|
...newCounter,
|
||||||
value: newCounter.initialValue
|
max: newCounter.max !== '' ? +newCounter.max : null,
|
||||||
|
value: +newCounter.initialValue
|
||||||
}
|
}
|
||||||
|
|
||||||
counters.add(counter);
|
counters.add(counter);
|
||||||
|
@ -60,10 +70,6 @@ function add(){
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.ok {
|
|
||||||
margin-left: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.app {
|
.app {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<div class="counter">
|
<div class="counter">
|
||||||
<header>{ counter.title }</header>
|
<header>{ counter.title }</header>
|
||||||
<span class="value">{ counter.value }</span>
|
<span class="value">{ counter.value }</span>
|
||||||
{#if counter.max}
|
{#if counter.max !== null}
|
||||||
<MyProgress value={ counter.value } max={ counter.max }></MyProgress>
|
<MyProgress value={ counter.value } max={ counter.max }></MyProgress>
|
||||||
{/if}
|
{/if}
|
||||||
<div class="controls">
|
<div class="controls">
|
||||||
|
@ -16,24 +16,28 @@
|
||||||
</div>
|
</div>
|
||||||
{#if showValueDialog}
|
{#if showValueDialog}
|
||||||
<div class="dialog">
|
<div class="dialog">
|
||||||
<div class="dialog-content">
|
<form class="dialog-content" novalidate bind:this={ dialogForm }>
|
||||||
<h1>{ showIncrement ? "Add" : "Set" }</h1>
|
<h1>{ showIncrement ? "Add" : "Set" }</h1>
|
||||||
<input class="dialog-value" type="text" inputmode="decimal" bind:value={ dialogValue } use:focus />
|
<input class="dialog-value" type="text" required pattern="(0|([1-9]\d*))(\.\d+)?" inputmode="decimal" bind:value={ dialogValue } use:focus />
|
||||||
<button on:click={ dialogCancel }>Cancel</button>
|
<div class="buttons">
|
||||||
<button class="ok" on:click={ dialogDone }>OK</button>
|
<button class="ok" on:click|preventDefault={ dialogDone }>OK</button>
|
||||||
|
<button on:click|preventDefault={ dialogCancel }>Cancel</button>
|
||||||
</div>
|
</div>
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
{#if showEditDialog}
|
{#if showEditDialog}
|
||||||
<div class="dialog">
|
<div class="dialog">
|
||||||
<div class="dialog-content">
|
<form class="dialog-content" novalidate bind:this={ dialogForm }>
|
||||||
<label>Name<input type="text" bind:value={editingCounter.title} use:focus/></label>
|
<label>Name<input type="text" required bind:value={editingCounter.title} use:focus/></label>
|
||||||
<label>Initial Value<input type="text" inputmode="decimal" bind:value={editingCounter.initialValue} /></label>
|
<label>Initial Value<input type="text" required pattern="(0|([1-9]\d*))(\.\d+)?" inputmode="decimal" bind:value={editingCounter.initialValue} /></label>
|
||||||
<label>Target<input type="text" inputmode="decimal" bind:value={editingCounter.max} /></label>
|
<label>Target<input type="text" pattern="(0|([1-9]\d*))(\.\d+)?" inputmode="decimal" bind:value={editingCounter.max} /></label>
|
||||||
<label>Save history<input type="checkbox" bind:checked={editingCounter.saveHistory} /></label>
|
<label>Save history<input type="checkbox" bind:checked={editingCounter.saveHistory} /></label>
|
||||||
<button on:click={ () => { showEditDialog = false; } }>Cancel</button>
|
<div class="buttons">
|
||||||
<button class="ok" on:click={ finishEdit }>OK</button>
|
<button class="ok" on:click|preventDefault={ finishEdit }>OK</button>
|
||||||
|
<button on:click|preventDefault={ () => { showEditDialog = false; } }>Cancel</button>
|
||||||
</div>
|
</div>
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
{#if showHistory}
|
{#if showHistory}
|
||||||
|
@ -56,6 +60,7 @@ let showSet;
|
||||||
let showEditDialog;
|
let showEditDialog;
|
||||||
let editingCounter;
|
let editingCounter;
|
||||||
let showHistory;
|
let showHistory;
|
||||||
|
let dialogForm;
|
||||||
|
|
||||||
$: showValueDialog = showIncrement || showSet;
|
$: showValueDialog = showIncrement || showSet;
|
||||||
|
|
||||||
|
@ -68,14 +73,23 @@ function update(newCounter){
|
||||||
}
|
}
|
||||||
|
|
||||||
function startEdit(e){
|
function startEdit(e){
|
||||||
e.stopPropagation();
|
editingCounter = { ...counter };
|
||||||
|
|
||||||
editingCounter = {...counter};
|
|
||||||
showEditDialog = true;
|
showEditDialog = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function finishEdit(){
|
function finishEdit(){
|
||||||
update(editingCounter);
|
if(!dialogForm.checkValidity()) {
|
||||||
|
dialogForm.removeAttribute('novalidate');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const updatedCounter = {
|
||||||
|
...editingCounter,
|
||||||
|
max: editingCounter.max !== null && editingCounter.max !== '' ? +editingCounter.max : null,
|
||||||
|
value: +editingCounter.value
|
||||||
|
}
|
||||||
|
|
||||||
|
update(updatedCounter);
|
||||||
showEditDialog = false;
|
showEditDialog = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,12 +99,17 @@ function dialogCancel(){
|
||||||
}
|
}
|
||||||
|
|
||||||
function dialogDone(){
|
function dialogDone(){
|
||||||
|
if(!dialogForm.checkValidity()) {
|
||||||
|
dialogForm.removeAttribute('novalidate');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const newCounter = showIncrement ? {
|
const newCounter = showIncrement ? {
|
||||||
...counter,
|
...counter,
|
||||||
value: counter.value + dialogValue
|
value: +counter.value + +dialogValue
|
||||||
} : {
|
} : {
|
||||||
...counter,
|
...counter,
|
||||||
value: dialogValue
|
value: +dialogValue
|
||||||
}
|
}
|
||||||
|
|
||||||
update(newCounter);
|
update(newCounter);
|
||||||
|
@ -101,12 +120,10 @@ function dialogDone(){
|
||||||
}
|
}
|
||||||
|
|
||||||
function reset(e){
|
function reset(e){
|
||||||
e.stopPropagation();
|
|
||||||
|
|
||||||
if(confirm(`Reset ${counter.title}?`)){
|
if(confirm(`Reset ${counter.title}?`)){
|
||||||
const newCounter = {
|
const newCounter = {
|
||||||
...counter,
|
...counter,
|
||||||
value: counter.initialValue
|
value: +counter.initialValue
|
||||||
}
|
}
|
||||||
|
|
||||||
update(newCounter);
|
update(newCounter);
|
||||||
|
@ -166,8 +183,4 @@ header {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin: 5px 0;
|
margin: 5px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ok {
|
|
||||||
margin-left: auto;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
|
@ -125,6 +125,13 @@ button:focus, button:hover {
|
||||||
width: auto;
|
width: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.dialog-content .buttons {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row-reverse;
|
||||||
|
justify-content: space-between;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
.dialog-content button:focus, .dialog-content button:hover {
|
.dialog-content button:focus, .dialog-content button:hover {
|
||||||
border: 0;
|
border: 0;
|
||||||
outline: 2px solid var(--button-color);
|
outline: 2px solid var(--button-color);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue