値の検証処理を実装します
src/js/msg/msg.json、src/js/msg/msg.{言語}.jsonを作成しましょう
{
"errorMinMaxLength" : "length min:${min} max:${max}"
,"errorMinMaxValue" : "value min:${min} max:${max}"
,"errorRadioValue" : "cannot change value"
,"errorRadiType" : "cannot wrong type"
,"errorCheckValue" : "cannot change value"
,"errorCheckType" : "cannot wrong type"
,"errorSelectedIndex" : "index min:${min} max:${max}"
,"errorSelectValue" : "option cannot wrong type"
,"errorRequired" : "required"
}
src/js/util/validator.jsを作成しましょう
export class Validator {
constructor() {
}
initValidate (target, property, newValue, oldValue, arg, event, untilNowResult) {
arg.msgObj.textContent = "";
return true;
}
propRequireValidate (target, property, newValue, oldValue, arg, event, untilNowResult) {
if (newValue === undefined || newValue === null || newValue === '') {
console.error(arg.name + ' : ' + $f.msg('errorRequired'));
return false;
} else {
return true;
}
}
propLengthValidate (target, property, newValue, oldValue, arg, event, untilNowResult) {
if (newValue !== undefined && newValue !== null && (newValue.length < arg.minLen || arg.maxLen < newValue.length)) {
console.error(arg.name + ' : ' + $f.msg('errorMinMaxLength', {'min': arg.minLen, 'max': arg.maxLen}));
return false;
} else {
return true;
}
}
textValidate (target, property, newValue, oldValue, arg, event, untilNowResult) {
if (newValue.length < arg.minLen || arg.maxLen < newValue.length) {
arg.msgObj.textContent = $f.msg('errorMinMaxLength', {'min': arg.minLen, 'max': arg.maxLen});
return false;
} else {
return true;
}
}
radioValueValidate (target, property, newValue, oldValue, arg, event, untilNowResult) {
if (newValue !== oldValue) {
arg.msgObj.textContent = $f.msg('errorRadioValue');
return false;
} else {
return true;
}
}
radioCheckValidate (target, property, newValue, oldValue, arg, event, untilNowResult) {
if (newValue !== true && newValue !== false) {
arg.msgObj.textContent = $f.msg('errorRadiType');
return false;
} else {
return true;
}
}
checkValueValidate (target, property, newValue, oldValue, arg, event, untilNowResult) {
if (newValue !== oldValue) {
arg.msgObj.textContent = $f.msg('errorCheckValue');
return false;
} else {
return true;
}
}
checkCheckValidate (target, property, newValue, oldValue, arg, event, untilNowResult) {
if (newValue !== true && newValue !== false) {
arg.msgObj.textContent = $f.msg('errorCheckType');
return false;
} else {
return true;
}
}
selectValueValidate (target, property, newValue, oldValue, arg, event, untilNowResult) {
if (!arg.values.has(newValue)) {
arg.msgObj.textContent = $f.msg('errorSelectValue');
return false;
} else {
return true;
}
}
selectIndexValidate (target, property, newValue, oldValue, arg, event, untilNowResult) {
if (newValue < arg.min || arg.max < newValue) {
arg.msgObj.textContent = $f.msg('errorSelectedIndex', {'min': arg.min, 'max': arg.max});
return false;
} else {
return true;
}
}
selectOptionValidate (target, property, newValue, oldValue, arg, event, untilNowResult) {
if (newValue !== true && newValue !== false) {
arg.msgObj.textContent = $f.msg('errorSelectValue');
return false;
} else {
return true;
}
}
}
src/js/modules/index.jsを修正しましょう
import {Validator} from '../util/validator.js';
export class Index {
constructor() {
this.prop1 = 'abc';
}
init() {
let v = new Validator();
$f.validate('group1', this.text, 'value', ['blur', null], [v.initValidate.bind(v), v.textValidate.bind(v)], {"minLen": 2, "maxLen": 4, "msgObj": this.bind1});
$f.validate('group1', this.radio1, 'value', ['input', null], [v.initValidate.bind(v), v.radioValueValidate.bind(v)], {"msgObj": this.bind2});
$f.validate('group1', this.radio1, 'checked', ['input', null], [v.initValidate.bind(v), v.radioCheckValidate.bind(v)], {"msgObj": this.bind2});
$f.validate('group1', this.radio2, 'value', ['input', null], [v.initValidate.bind(v), v.radioValueValidate.bind(v)], {"msgObj": this.bind2});
$f.validate('group1', this.radio2, 'checked', ['input', null], [v.initValidate.bind(v), v.radioCheckValidate.bind(v)], {"msgObj": this.bind2});
$f.validate('group1', this.checkbox, 'value', ['input', null], [v.initValidate.bind(v), v.checkValueValidate.bind(v)], {"msgObj": this.bind4});
$f.validate('group1', this.checkbox, 'checked', ['input', null], [v.initValidate.bind(v), v.checkCheckValidate.bind(v)], {"msgObj": this.bind4});
$f.validate('group1', this.singleSelect, 'value', ['input', null], [v.initValidate.bind(v), v.selectValueValidate.bind(v)], {"values": new Set(["aa", "bb", "cc"]), "msgObj": this.bind5});
$f.validate('group1', this.singleSelect, 'selectedIndex', [null], [v.initValidate.bind(v), v.selectIndexValidate.bind(v)], {"min": 0, "max": 2, "msgObj": this.bind5});
$f.validate('group1', this.singleSelect.options[0], 'selected', [null], [v.initValidate.bind(v), v.selectOptionValidate.bind(v)], {"msgObj": this.bind5});
$f.validate('group1', this.singleSelect.options[1], 'selected', [null], [v.initValidate.bind(v), v.selectOptionValidate.bind(v)], {"msgObj": this.bind5});
$f.validate('group1', this.singleSelect.options[2], 'selected', [null], [v.initValidate.bind(v), v.selectOptionValidate.bind(v)], {"msgObj": this.bind5});
$f.validate('group1', this.multipleSelect, 'value', ['input', null], [v.initValidate.bind(v), v.selectValueValidate.bind(v)], {"values": new Set(["aaa", "bbb", "ccc"]), "msgObj": this.bind7});
$f.validate('group1', this.multipleSelect, 'selectedIndex', [null], [v.initValidate.bind(v), v.selectIndexValidate.bind(v)], {"min": 0, "max": 2, "msgObj": this.bind7});
$f.validate('group1', this.multipleSelect.options[0], 'selected', [null], [v.initValidate.bind(v), v.selectOptionValidate.bind(v)], {"msgObj": this.bind7});
$f.validate('group1', this.multipleSelect.options[1], 'selected', [null], [v.initValidate.bind(v), v.selectOptionValidate.bind(v)], {"msgObj": this.bind7});
$f.validate('group1', this.multipleSelect.options[2], 'selected', [null], [v.initValidate.bind(v), v.selectOptionValidate.bind(v)], {"msgObj": this.bind7});
$f.validate('group1', this.textarea, 'value', ['blur', null], [v.initValidate.bind(v), v.textValidate.bind(v)], {"minLen": 5, "maxLen": 10, "msgObj": this.bind9});
$f.validate('group1', this, 'prop1', [null], [v.propRequireValidate.bind(v), v.propLengthValidate.bind(v)], {"minLen": 2, "maxLen": 4, "name": "Index->prop1"});
}
btn_click(event) {
this.text.value = '12345';
this.radio1.value = 'a';
this.radio1.checked = 'a';
this.radio2.value = 'a';
this.radio2.checked = 'a';
this.checkbox.value = 'a';
this.checkbox.checked = 'a';
this.singleSelect.value = 3;
this.singleSelect.selectedIndex = 3;
this.singleSelect.options[0].selected = 'a';
this.singleSelect.options[1].selected = 'a';
this.singleSelect.options[2].selected = 'a';
this.multipleSelect.value = 3;
this.multipleSelect.selectedIndex = 3;
this.multipleSelect.options[0].selected = 'a';
this.multipleSelect.options[1].selected = 'a';
this.multipleSelect.options[2].selected = 'a';
this.textarea.value = '12345678901';
this.prop1 = 'abcdef';
}
}
src/page/index.htmlを修正しましょう
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title>
sample
</title>
<script id="fs-js" src="http://localhost:8000/js/fairysupport.min.js" data-page-root="http://localhost:8000/page"></script>
</head>
<body>
<div data-obj="bind1"></div>
<div><input type="text" data-obj="text" value="1234"></div>
<div data-obj="bind2"></div>
<div><input type="radio" data-obj="radio1" name="radio" value="1"><input type="radio" data-obj="radio2" name="radio" value="2"></div>
<div data-obj="bind4"></div>
<div><input type="checkbox" data-obj="checkbox" value="1"></div>
<div data-obj="bind5"></div>
<div data-obj="bind6"></div>
<div>
<select data-obj="singleSelect">
<option value="aa" selected>aa_val</option>
<option value="bb">bb_val</option>
<option value="cc">cc_val</option>
</select>
</div>
<div data-obj="bind7"></div>
<div data-obj="bind8"></div>
<div>
<select data-obj="multipleSelect" multiple>
<option value="aaa" selected>aaa_val</option>
<option value="bbb">bbb_val</option>
<option value="ccc">ccc_val</option>
</select>
</div>
<div data-obj="bind9"></div>
<div><textarea cols="10" rows="10" data-obj="textarea">12345</textarea></div>
<div><input type="button" data-name="btn" value="set"></div>
</body>
</html>
index.jsで使っている$f.validateメソッドは、第2引数オブジェクトに第4引数イベントが発生するとき、第5引数に渡した関数を実行するメソッドです
例えば、$f.validate('group1', this.text, 'value', ['blur'], [v.initValidate.bind(v), v.textValidate.bind(v)], {"minLen": 2, "maxLen": 4, "msgObj": this.bind1});の場合
this.textオブジェクトにblurイベントが発生したとき、ValidatorクラスのinitValidate、textValidateメソッドが実行されます
第4引数には配列で複数イベントを渡すことができます。nullを渡すと第2引数の第3引数プロパティに=演算子で値を格納する時という意味になります
例えば、$f.validate('group1', this.text, 'value', [null], [v.initValidate.bind(v), v.textValidate.bind(v)], {"minLen": 2, "maxLen": 4, "msgObj": this.bind1});の場合
this.textオブジェクトのvalueプロパティに=演算子で値が格納されるとき、ValidatorクラスのinitValidate、textValidateメソッドが実行されます
$f.validateの第5引数に渡される関数は引数を7つ取ります
第1引数:$f.validateの第2引数に渡した値
第2引数:$f.validateの第3引数に渡した値
第3引数:第2引数の第3引数プロパティに格納する値
第4引数:focus、blur、=演算子、Validatorによるtrue返却の4つの内、直近で発生したイベントによって格納された値。この値は、$f.validateの第4引数の要素(イベント)ごとに管理されます。つまり、Validatorによるtrue返却によって設定された値は、Validatorが実行されたイベントのoldValueを上書きますが、他のイベントのoldValueは上書きません。
第5引数:$f.validateの第6引数に渡した値
第6引数:イベントオブジェクト
第7引数:boolean。$f.validateの第5引数に渡された関数が1回でもfalseを返している場合、false、$f.validateの第5引数に渡された関数が全てtrueを返している場合true
以降、$f.validateの第5引数に渡された関数をValidatorと呼びます
Validatorの戻り値はbooleanです。全てのValidatorがtrueを返すと$f.validateの第2引数オブジェクトの第3引数プロパティにValidatorの第3引数を格納します。Validatorが1つでもfalseを返すと$f.validateの第2引数オブジェクトの第3引数プロパティにValidatorの第4引数を格納します。
手動実行
src/js/modules/index.jsを修正しましょう
import {Validator} from '../util/validator.js';
export class Index {
constructor() {
this.prop1 = 'abc';
}
init() {
let v = new Validator();
$f.validate('group1', this.text, 'value', ['blur', null], [v.initValidate.bind(v), v.textValidate.bind(v)], {"minLen": 2, "maxLen": 4, "msgObj": this.bind1});
$f.validate('group1', this.radio1, 'value', ['input', null], [v.initValidate.bind(v), v.radioValueValidate.bind(v)], {"msgObj": this.bind2});
$f.validate('group1', this.radio1, 'checked', ['input', null], [v.initValidate.bind(v), v.radioCheckValidate.bind(v)], {"msgObj": this.bind2});
$f.validate('group1', this.radio2, 'value', ['input', null], [v.initValidate.bind(v), v.radioValueValidate.bind(v)], {"msgObj": this.bind2});
$f.validate('group1', this.radio2, 'checked', ['input', null], [v.initValidate.bind(v), v.radioCheckValidate.bind(v)], {"msgObj": this.bind2});
$f.validate('group1', this.checkbox, 'value', ['input', null], [v.initValidate.bind(v), v.checkValueValidate.bind(v)], {"msgObj": this.bind4});
$f.validate('group1', this.checkbox, 'checked', ['input', null], [v.initValidate.bind(v), v.checkCheckValidate.bind(v)], {"msgObj": this.bind4});
$f.validate('group1', this.singleSelect, 'value', ['input', null], [v.initValidate.bind(v), v.selectValueValidate.bind(v)], {"values": new Set(["aa", "bb", "cc"]), "msgObj": this.bind5});
$f.validate('group1', this.singleSelect, 'selectedIndex', [null], [v.initValidate.bind(v), v.selectIndexValidate.bind(v)], {"min": 0, "max": 2, "msgObj": this.bind5});
$f.validate('group1', this.singleSelect.options[0], 'selected', [null], [v.initValidate.bind(v), v.selectOptionValidate.bind(v)], {"msgObj": this.bind5});
$f.validate('group1', this.singleSelect.options[1], 'selected', [null], [v.initValidate.bind(v), v.selectOptionValidate.bind(v)], {"msgObj": this.bind5});
$f.validate('group1', this.singleSelect.options[2], 'selected', [null], [v.initValidate.bind(v), v.selectOptionValidate.bind(v)], {"msgObj": this.bind5});
$f.validate('group1', this.multipleSelect, 'value', ['input', null], [v.initValidate.bind(v), v.selectValueValidate.bind(v)], {"values": new Set(["aaa", "bbb", "ccc"]), "msgObj": this.bind7});
$f.validate('group1', this.multipleSelect, 'selectedIndex', [null], [v.initValidate.bind(v), v.selectIndexValidate.bind(v)], {"min": 0, "max": 2, "msgObj": this.bind7});
$f.validate('group1', this.multipleSelect.options[0], 'selected', [null], [v.initValidate.bind(v), v.selectOptionValidate.bind(v)], {"msgObj": this.bind7});
$f.validate('group1', this.multipleSelect.options[1], 'selected', [null], [v.initValidate.bind(v), v.selectOptionValidate.bind(v)], {"msgObj": this.bind7});
$f.validate('group1', this.multipleSelect.options[2], 'selected', [null], [v.initValidate.bind(v), v.selectOptionValidate.bind(v)], {"msgObj": this.bind7});
$f.validate('group1', this.textarea, 'value', ['blur', null], [v.initValidate.bind(v), v.textValidate.bind(v)], {"minLen": 5, "maxLen": 10, "msgObj": this.bind9});
$f.validate('group1', this, 'prop1', [null], [v.propRequireValidate.bind(v), v.propLengthValidate.bind(v)], {"minLen": 2, "maxLen": 4, "name": "Index->prop1"});
}
btn_click(event) {
console.log($f.execValidator('group1', this.text));
let vaild = $f.execGroupValidator('group1');
if (!vaild) {
event.preventDefault();
event.stopImmediatePropagation();
return;
}
}
}
execValidatorは、$f.validateの第1引数、第2引数に合致するValidatorを実行します
execValidatorは、終了処理の戻り値でoldValueのキーがあっても無視します。oldValueAllEvent、oldValueSpecificEventのキーを無視しません。第3引数にtrueが渡された場合、forceNewValue、newValueのキーを無視しません。
execGroupValidatorは、$f.validateの第1引数に合致するValidatorを実行します
execGroupValidatorは、終了処理の戻り値でoldValueのキーがあっても無視します。oldValueAllEvent、oldValueSpecificEventのキーを無視しません。第2引数にtrueが渡された場合、forceNewValue、newValueのキーを無視しません。
$f.validateの第1引数には文字列の他にオブジェクトを渡すこともできます
終了処理については下記で説明します
終了処理
src/js/util/validator.jsを変更しましょう
export class Validator {
constructor() {
}
initValidate (target, property, newValue, oldValue, arg, event, untilNowResult) {
arg.msgObj.textContent = "";
return true;
}
textValidate (target, property, newValue, oldValue, arg, event, untilNowResult) {
if (newValue.length < arg.minLen || arg.maxLen < newValue.length) {
arg.msgObj.textContent = $f.msg('errorMinMaxLength', {'min': arg.minLen, 'max': arg.maxLen});
return false;
} else {
return true;
}
}
textFinalize (target, property, newValue, oldValue, arg, event, valid, validResult) {
let result = {};
if (event && 'type' in event && 'input' === event.type) {
result['forceNewValue'] = newValue;
if (valid) {
result['oldValueAllEvent'] = newValue;
}
}
return result;
}
}
src/js/modules/index.jsを変更しましょう
import {Validator} from '../util/validator.js';
export class Index {
constructor() {
this.prop1 = 'abc';
}
init() {
let v = new Validator();
$f.validate('group1', this.text, 'value', ['input', 'blur', null], [v.initValidate.bind(v), v.textValidate.bind(v)], {"minLen": 2, "maxLen": 4, "msgObj": this.bind1}, v.textFinalize.bind(v));
}
}
src/page/index.htmlを修正しましょう
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title>
sample
</title>
<script id="fs-js" src="http://localhost:8000/js/fairysupport.min.js" data-page-root="http://localhost:8000/page"></script>
</head>
<body>
<div data-obj="bind1"></div>
<div><input type="text" data-obj="text" value="1234"></div>
</body>
</html>
以降、$f.validateの第5引数に渡された関数をValidatorと呼びます
$f.validateの第7引数に終了処理を渡すことができます
$f.validateの第7引数に渡される関数は引数を8つ取ります
第1~6引数:Validatorの引数と同じ
第7引数:boolean。Validatorの内、1つでもfalseを返していれば、false
第8引数:オブジェクト。キーはValidatorの戻り値。値は配列でValidator名
$f.validateの第六引数に渡される関数の戻り値はオブジェクトです。オブジェクトの内容は下記です
キー:newValue、値:Validatorの第3引数を置きかえます
キー:forceNewValue、値:Validatorの第3引数を置きかえます。さらに、Validator終了処理の第7引数がfalseであっても、第2引数の第3引数プロパティの値をこの値で上書きます。
キー:oldValue、値:Validatorの第4引数。Validatorの第4引数は、$f.validateの第4引数の要素(イベント)ごとに管理されます。Validatorの第6引数イベントにひもづくValidatorの第4引数を置きかえます
キー:oldValueAllEvent、値:Validatorの第4引数。Validatorの第4引数は、$f.validateの第4引数の要素(イベント)ごとに管理されます。$f.validateの第4引数に渡された全イベントにひもづくValidatorの第4引数を置きかえます
キー:oldValueSpecificEvent、値:オブジェクト。キーがイベント名、値がValidatorの第4引数。Validatorの第4引数は、$f.validateの第4引数の要素(イベント)ごとに管理されます。$f.validateの第4引数に渡されたイベントの内このオブジェクトのキーに合致するイベントにひもづくValidatorの第4引数を置きかえます
直近結果取得
src/js/modules/index.jsを変更しましょう
import {Validator} from '../util/validator.js';
export class Index {
constructor() {
this.prop1 = 'abc';
}
init() {
let v = new Validator();
$f.validate('group1', this.text, 'value', ['input', 'blur', null], [v.initValidate.bind(v), v.textValidate.bind(v)], {"minLen": 2, "maxLen": 4, "msgObj": this.bind1}, v.textFinalize.bind(v));
}
btn_click(event) {
console.log($f.getValidateLatestResult('group1', this.text, 'value', 'blur'));
}
}
src/page/index.htmlを修正しましょう
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title>
sample
</title>
<script id="fs-js" src="http://localhost:8000/js/fairysupport.min.js" data-page-root="http://localhost:8000/page"></script>
</head>
<body>
<div data-obj="bind1"></div>
<div><input type="text" data-obj="text" value="1234"></div>
<div><input type="button" data-name="btn" value="LatestResult"></div>
</body>
</html>
getValidateLatestResultは、getValidateLatestResultに渡された引数が$f.validateの第1~3引数に合致し、$f.validateの第4引数のどれかに合致するValidatorの直近の結果を返します