JavaScript Framework fairy support js
Validate

Create a value validation process.
Let's create src/js/msg/msg.json and src/js/msg/msg.{language}.json.

src/js/msg/msg.json and src/js/msg/msg.{language}.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"
}

Let's create src/js/util/validator.js.

src/js/util/validator.js
export class Validator {

    constructor() {
    }

    initValidate (target, property, newValue, oldValue, arg, event) {
        arg.msgObj.textContent = "";
        return true;
    }

    propRequireValidate (target, property, newValue, oldValue, arg, event) {
        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) {
        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) {
        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) {
        if (newValue !== oldValue) {
            arg.msgObj.textContent = $f.msg('errorRadioValue');
            return false;
        } else {
            return true;
        }
    }

    radioCheckValidate (target, property, newValue, oldValue, arg, event) {
        if (newValue !== true && newValue !== false) {
            arg.msgObj.textContent = $f.msg('errorRadiType');
            return false;
        } else {
            return true;
        }
    }

    checkValueValidate (target, property, newValue, oldValue, arg, event) {
        if (newValue !== oldValue) {
            arg.msgObj.textContent = $f.msg('errorCheckValue');
            return false;
        } else {
            return true;
        }
    }

    checkCheckValidate (target, property, newValue, oldValue, arg, event) {
        if (newValue !== true && newValue !== false) {
            arg.msgObj.textContent = $f.msg('errorCheckType');
            return false;
        } else {
            return true;
        }
    }

    selectValueValidate (target, property, newValue, oldValue, arg, event) {
        if (!arg.values.has(newValue)) {
            arg.msgObj.textContent = $f.msg('errorSelectValue');
            return false;
        } else {
            return true;
        }
    }

    selectIndexValidate (target, property, newValue, oldValue, arg, event) {
        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) {
        if (newValue !== true && newValue !== false) {
            arg.msgObj.textContent = $f.msg('errorSelectValue');
            return false;
        } else {
            return true;
        }
    }

}

Let's change src/js/modules/index.js.

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';
    }
}

Let's change src/page/index.html.

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>

The $f.validate method used in index.js is the method that executes the function passed to the 5th argument when the 4th argument event occurs in the 2nd argument object.
For example, in the case of $f.validate('group1', this.text, 'value', ['blur'], [v.initValidate.bind(v), v.textValidate.bind(v)], {"minLen": 2, "maxLen": 4, "msgObj": this.bind1}); when the blur event occurs in this.text object, the initValidate and textValidate methods of the Validator class are executed.
You can pass multiple events in an array as the 4th argument. If you pass null, it means when you store the value in the 3rd argument property of the 2nd argument using the = operator.
For example, in the case of $f.validate('group1', this.text, 'value', [null], [v.initValidate.bind(v), v.textValidate.bind(v)], {"minLen": 2, "maxLen": 4, "msgObj": this.bind1}); when you store the value in the value property of this.text object using the = operator, the initValidate and textValidate methods of the Validator class are executed.
The function passed to the 5th argument of $f.validate takes 6 arguments.
1st argument: Value passed to the 2nd argument of $f.validate.
2nd argument: Value passed to the 3rd argument of $f.validate.
3rd argument: Value to be stored in the 3rd argument property of the 2nd argument.
4th argument: focus, blur, = operator or true return by Validator, the value stored by the most recently generated event. This value is managed for each element (event) of the 4th argument of $f.validate. That is, the value set by the true return by the Validator overwrites the oldValue of the event that ran the Validator, but not the oldValue of the other events.
5th argument: Value passed to the 6th argument of $f.validate.
6th argument: Event object.
Hereafter, the function passed to the 5th argument of $f.validate is called Validator.
The return value of Validator is boolean. If all Validators return true, the 3rd argument of Validator is stored in the 3rd argument property of the 2nd argument object of $f.validate. If even one Validator returns false, the 4th argument of Validator is stored in the 3rd argument property of the 2nd argument object of $f.validate.


Manual execution

Let's change src/js/modules/index.js

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 executes Validator that matches the 1st and 2nd arguments of $f.validate.
execValidator ignores the oldValue key in the return value of the end processing. execValidator does not ignore the oldValueAllEvent and oldValueSpecificEvent keys. execValidator does not ignore the forceNewValue and newValue keys when true is passed as the 3rd argument.
execGroupValidator executes a Validator that matches the first argument of $f.validate.
execGroupValidator ignores the oldValue key in the return value of the end processing. execGroupValidator does not ignore the oldValueAllEvent and oldValueSpecificEvent keys. execGroupValidator does not ignore the forceNewValue and newValue keys when true is passed as the 2nd argument.
The end processing is explained below.


End processing

Let's change src/js/util/validator.js

src/js/util/validator.js
export class Validator {

    constructor() {
    }

    initValidate (target, property, newValue, oldValue, arg, event) {
        arg.msgObj.textContent = "";
        return true;
    }

    textValidate (target, property, newValue, oldValue, arg, event) {
        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;
    }
    
}

Let's change src/js/modules/index.js

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));

    }

}

Let's change src/page/index.html

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>

Hereafter, the function passed to the 5th argument of $f.validate is called Validator.
You can pass the end processing to the 7th argument of $f.validate.
The function passed to the 7th argument of $f.validate takes 8 arguments.
1st to 6th arguments: Same as Validator arguments.
7th argument: boolean. If even one of the Validators returns false, it is false.
8th argument: Object. The key is the return value of Validator. The value is an array and the Validator name.
The return value of the function passed to the 6th argument of $f.validate is an object. The contents of the object are as follows.
Key: newValue, Value: Replaces the 3rd argument of Validator.
Key: forceNewValue, Value: Replaces the 3rd argument of Validator. Furthermore, even if the 7th argument of End processing is false, it overwrites the value of the 3rd argument property of the 2nd argument with this value.
Key: oldValue, Value: 4th argument of Validator. The 4th argument of Validator is managed for each element (event) of the 4th argument of $f.validate. Replaces the 4th argument of the Validator associated with the 6th argument event of the Validator.
Key: oldValueAllEvent, Value: Validator 4th argument. The 4th argument of Validator is managed for each element (event) of the 4th argument of $f.validate. Replaces the 4th argument of Validator associated with all events passed in the 4th argument of $f.validate.
Key: oldValueSpecificEvent, Value: the object that key is the event name, value is the 4th argument of Validator. The 4th argument of Validator is managed for each element (event) of the 4th argument of $f.validate. Replaces the 4th argument of Validator associated with the event that matches the key of this object among the events passed to the 4th argument of $f.validate.


Get the most recent result

Let's change src/js/modules/index.js

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'));
    
    }
}

Let's change src/page/index.html

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 returns the most recent Validator result where the argument passed to getValidateLatestResult matches the first to third arguments of $f.validate and one of the fourth arguments of $f.validate.


Next page Holding the value

table of contents