Add input validation

This commit is contained in:
Pieter Vander Vennet 2020-07-23 17:32:18 +02:00
parent ef593654f4
commit 1488caf362
8 changed files with 66 additions and 17 deletions

View file

@ -8,6 +8,7 @@ import {ImageCarouselWithUploadConstructor} from "../../UI/Image/ImageCarouselWi
import BikeStationOperator from "../Questions/bike/StationOperator";
import Translations from "../../UI/i18n/Translations";
import ParkingOperator from "../Questions/bike/ParkingOperator";
import {TagRenderingOptions} from "../TagRendering";
export default class BikeParkings extends LayerDefinition {
@ -27,7 +28,15 @@ export default class BikeParkings extends LayerDefinition {
this.elementsToShow = [
new ImageCarouselWithUploadConstructor(),
//new ParkingOperator(),
new ParkingType()
new ParkingType(),
new TagRenderingOptions({
question: "How many bicycles fit in this bicycle parking?",
freeform: {
key: "capacity",
renderTemplate: "Place for {capacity} bikes",
template: "$nat$ bikes fit in here"
}
})
];
this.wayHandling = LayerDefinition.WAYHANDLING_CENTER_AND_WAY;

View file

@ -15,9 +15,19 @@ import {FixedInputElement} from "../UI/Input/FixedInputElement";
import {RadioButton} from "../UI/Input/RadioButton";
import Translations from "../UI/i18n/Translations";
import Locale from "../UI/i18n/Locale";
import {FloatField, IntField, StringField} from "../UI/Input/PhoneField";
export class TagRenderingOptions implements TagDependantUIElementConstructor {
public static inputValidation = {
"$": (str) => true,
"string": (str) => true,
"int": (str) => str.indexOf(".") < 0 && !isNaN(Number(str)),
"nat": (str) => str.indexOf(".") < 0 && !isNaN(Number(str)) && Number(str) > 0,
"float": (str) => !isNaN(Number(str)),
}
/**
* Notes: by not giving a 'question', one disables the question form alltogether
*/
@ -334,13 +344,20 @@ class TagRendering extends UIElement implements TagDependantUIElement {
return undefined;
}
const prepost = Translations.W(freeform.template).InnerRender().split("$");
const type = prepost[1];
const isValid = TagRenderingOptions.inputValidation[type];
const pickString =
(string) => {
(string: any) => {
if (string === "" || string === undefined) {
return undefined;
}
if (!isValid(string)) {
return undefined;
}
const tag = new Tag(freeform.key, string);
if (freeform.extraTags === undefined) {
return tag;
}
@ -369,8 +386,7 @@ class TagRendering extends UIElement implements TagDependantUIElement {
toString: toString
});
const prepost = Translations.W(freeform.template).InnerRender().split("$$$");
return new InputElementWrapper(prepost[0], textField, prepost[1]);
return new InputElementWrapper(prepost[0], textField, prepost[2]);
}

View file

@ -5,11 +5,12 @@ import {UIEventSource} from "../UI/UIEventSource";
export class QueryParameters {
private static order: string [] = ["layout","test","zoom","lat","lon"];
private static order: string [] = ["layout","test","z","lat","lon"];
private static knownSources = QueryParameters.init();
private static addOrder(key){
if(this.order.indexOf(key) < 0){
console.log("Adding order", key)
this.order.push(key)
}
}

View file

@ -9,3 +9,4 @@ export abstract class InputElement<T> extends UIElement{
abstract IsValid(t: T) : boolean;
}

View file

@ -1,7 +1,6 @@
import {UIElement} from "../UIElement";
import {UIEventSource} from "../UIEventSource";
import {InputElement} from "./InputElement";
import {FixedUiElement} from "../Base/FixedUiElement";
import Translations from "../i18n/Translations";
@ -17,9 +16,23 @@ export class TextField<T> extends InputElement<T> {
private _fromString?: (string: string) => T;
private _toString: (t: T) => string;
constructor(options: {
/**
* Shown as placeholder
*/
placeholder?: string | UIElement,
/**
* Converts the T to a (canonical) string
* @param t
*/
toString: (t: T) => string,
/**
* Converts the string to a T
* Returns undefined if invalid
* @param string
*/
fromString: (string: string) => T,
value?: UIEventSource<T>
}) {
@ -66,9 +79,9 @@ export class TextField<T> extends InputElement<T> {
}
InnerRender(): string {
return "<form onSubmit='return false' class='form-text-field'>" +
"<input type='text' placeholder='" + this._placeholder.InnerRender() + "' id='text-" + this.id + "'>" +
"</form>";
return `<form onSubmit='return false' class='form-text-field'>` +
`<input type='text' placeholder='${this._placeholder.InnerRender()}' id='text-${this.id}'>` +
`</form>`;
}
InnerUpdate() {
@ -76,6 +89,11 @@ export class TextField<T> extends InputElement<T> {
if (field === null) {
return;
}
this.mappedValue.addCallback((data) => {
field.className = this.mappedValue.data !== undefined ? "valid" : "invalid";
});
const self = this;
field.oninput = () => {
// @ts-ignore

View file

@ -386,6 +386,10 @@ export default class Translations {
skippedQuestions: new T({
en: "Some questions are skipped",
nl: "Sommige vragen zijn overgeslaan"
}),
number: new T({
en: "number",
nl: "getal"
})
}
}

View file

@ -12,6 +12,10 @@ form {
display: inline;
}
.invalid {
box-shadow: 0 0 10px #ff5353;
}
#leafletDiv {
height: 100%;
}

10
test.ts
View file

@ -1,9 +1,5 @@
import {QueryParameters} from "./Logic/QueryParameters";
import {IntField} from "./UI/Input/PhoneField";
console.log("Hi");
const layout = QueryParameters.GetQueryParameter("layout").addCallback(console.log)
console.log("Layout is", layout.data)
window.setTimeout(() => {layout.setData("XXX"), 2000})
const f = new IntField().AttachTo("maindiv")
f.GetValue().addCallback(console.log)