使用微风实用淘汰赛验证?(knockout validation using breeze util

2019-07-04 09:19发布

有没有人写了一个实用工具,将微风的元数据(从实体框架数据属性捕获)转换为淘汰赛扩展验证(使用knockout.validation)?

Answer 1:

我已经从一个实体读取元数据,并增加了验证规则的功能。

app.domain.indicador = (function () {
"use strict";
var constructor = function () {...}
var initializer = function indicadorInitializer(entity) {
    var entityType = entity.entityType;
    if (entityType) {
        console.log(entityType);
        for (var i = 0; i < entityType.dataProperties.length; i++) {
            var property = entityType.dataProperties[i];
            console.log(property);
            var propertyName = property.name;

            var propertyObject = entity[propertyName];
            if (!property.isNullable) {
                propertyObject.extend({ required: true });
            }
            if (property.maxLength) {
                propertyObject.extend({ maxLength: property.maxLength });
            }
        }

        for (var i = 0; i < entityType.foreignKeyProperties.length; i++) {
            var property = entityType.foreignKeyProperties[i];
            console.log(property);
            var propertyName = property.name;

            var propertyObject = entity[propertyName];
            if (!property.isNullable) {
                propertyObject.extend({ required: true });
            }
            if (property.maxLength) {
                propertyObject.extend({ maxLength: property.maxLength });
            }
            //Bussines rule
            propertyObject.extend({ notEqual: 0 });
        }
    }
};
return {
    constructor: constructor,
    initializer: initializer
};
})();

我用的是功能初始化:

store.registerEntityTypeCtor("Indicador", domain.indicador.constructor, domain.indicador.initializer);

这只是一个开始,但对于时间对我来说非常有用。

更新:

我改变了我添加验证的方式。 我在这里分享它的情况下,它是有用的人:

辅助对象:

app.validatorHelper = (function (breeze) {
var foreignKeyInvalidValue = 0;

function addDataTypeRules(dataType, property) {
    switch (dataType) {
        case breeze.DataType.DateTime:
            //TODO: implement my function to validate dates. This validator is too permissive
            property.extend({ date: true });
            break;
        case breeze.DataType.Int64:
        case breeze.DataType.Int32:
        case breeze.DataType.Int16:
            //it's needed to accept negative numbers because of the autogenerated keys
            property.extend({ signedDigit: true });
            break;
        case breeze.DataType.Decimal:
        case breeze.DataType.Double:
        case breeze.DataType.Single:
            property.extend({ number: true });
            break;
    }
};

function addValidationRules(entity) {
    var entityType = entity.entityType;
    if (entityType) {
        for (var i = 0; i < entityType.dataProperties.length; i++) {
            var property = entityType.dataProperties[i];
            //console.log(property);
            var propertyName = property.name;
            var propertyObject = entity[propertyName];

            addDataTypeRules(property.dataType, propertyObject);

            if (!property.isNullable) {
                propertyObject.extend({ required: true });
            }
            if (property.maxLength) {
                propertyObject.extend({ maxLength: property.maxLength });
            }
        }

        for (var i = 0; i < entityType.foreignKeyProperties.length; i++) {
            var property = entityType.foreignKeyProperties[i];
            //console.log(property);
            var propertyName = property.name;
            var propertyObject = entity[propertyName];

            addDataTypeRules(property.dataType, propertyObject);

            if (!property.isNullable) {
                propertyObject.extend({ required: true });
                //Bussiness Rule: 0 is not allowed for required foreign keys
                propertyObject.extend({ notEqual: foreignKeyInvalidValue });
            }
            if (property.maxLength) {
                propertyObject.extend({ maxLength: property.maxLength });
            }
        }
    }
};

return {
    addValidationRules: addValidationRules
};
})(breeze);

自定义验证:

(function (ko) {
ko.validation.rules['signedDigit'] = {
    validator: function (value, validate) {
        if (!validate) return true;
        return ko.validation.utils.isEmptyVal(value) || (validate && /^-?\d+$/.test(value));
    },
    message: 'Please enter a digit'
};

ko.validation.registerExtenders();
})(ko);

使用在初始化助手:

app.domain.valorIndicador = (function (vHelper) {
"use strict";
var constructor = function () {
};

var initializer = function indicadorInitializer(entity) {
    vHelper.addValidationRules(entity);
};

return {
    constructor: constructor,
    initializer: initializer
};
})(app.validatorHelper);

并设置初始化:

store.registerEntityTypeCtor("ValorIndicador", domain.valorIndicador.constructor, domain.valorIndicador.initializer);


Answer 2:

一个简单的方法来使用淘汰赛从breezejs绑定验证错误。

我们可以订阅从entityAspect validationErrorsChanged事件:

function subscribeValidation() {
    return self.entity().entityAspect.validationErrorsChanged.subscribe(function (validationChangeArgs) {
                validationChangeArgs.added.forEach(function (item) { addError(item); });
                validationChangeArgs.removed.forEach(function (item) { self.validationErrors.remove(item); });
    });
}

this.hasError = function (propertyName) {
    var array = self.validationErrors();
    var match = array.filter(function (item) {
        return item.propertyName == propertyName;
    });
    if (match.length > 0) {
        return true;
    } else return false;
};


function addError(item) {
    self.validationErrors.remove(function (i) {
        return i.propertyName == item.propertyName;
    });

    self.validationErrors.push(item);
}

最后,我们可以绑定到消息的UI(我使用Twitter的自举CSS类)

<div class="control-group" data-bind="css: { 'error': hasError('Nome') }">
    <label class="control-label">Nome</label>
    <div class="controls">
        <input type="text" class="input-xxlarge" data-bind="value: model().Nome">
        <span class="help-inline" data-bind="text: getErrorMessage('Nome')"></span>
    </div>
</div>

查看完整的要点在这里



Answer 3:

当我开始使用带有淘汰赛微风,然后我不得不有关如何验证的东西,以及如何显示验证内嵌完全相同的问题,我以前搜查这一点。

考虑到微风已经验证了内置的,我决定写一个自定义的淘汰赛绑定每次都显示验证结果的可观察值的变化,这是很容易的毕竟:

这里的自定义绑定:

    ko.bindingHandlers.breezeValidate = {
    init: function (element, valueAccessor, allBindingsAccessor, context) {
        var isOk = context.entityAspect.validateProperty(valueAccessor());
        var errors = context.entityAspect.getValidationErrors(valueAccessor());
        var message = "";
        if (errors.length > 0)
            message = errors[0].errorMessage;
        $(element).html(message);
    },

    //update the control when the view model changes
    update: function (element, valueAccessor, allBindingsAccessor, context) {
        debugger;
        this.init(element, valueAccessor, allBindingsAccessor, context)
    }
};

和用法是这样的:

<span data-bind="text: Name"></span>
<span data-bind="breezeValidate: 'Name'"></span>

这工作,因为这行:

var isOk = context.entityAspect.validateProperty(valueAccessor());

当请求微风来验证它最终调用观察到的财产,它被淘汰赛注册,所以每次它改变时,这种结合将再次调用,该错误信息将随之更新。

我只是表示第一验证消息,当然你可以遍历直通所有的人,甚至添加不同风格的元素。

希望这可以帮助!!



Answer 4:

不知道为什么人们会想用ko.validation - 它只是复制处理微风的客户端是无论如何做。 而鉴于微风开发商暗示的验证很快就会更强大,何必呢。

于是,我开始与蒂亚戈 - 奥利维拉的伟大的工作。 但我想有标记的最低限度。 假设使用自举类和从先前元素,我可以简化最标记补充拖欠验证属性名称:

<span class="help-inline" data-bind="breezeValidation: null"></span>

赢得!

我ko.bindingHandler:

//Highlight field in red & show first validation message
//
//Outputs first validation message for 'propertyName' or if null: previous controls value binding
//Needs ancestor with 'control-group' class to set class 'error' for Bootstrap error display
//
//Example:
//<td class="control-group">
//    <input class="input-block-level text-right" data-bind="value: id" />
//    <span class="help-inline" data-bind="breezeValidation: null"></span>
//</td>
//
//Does not and cannot validate keys that already exist in cache. knockout write calls breeze which throws uncaught error

ko.bindingHandlers.breezeValidation = {
    init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
        // This will be called when the binding is first applied to an element
        // Set up any initial state, event handlers, etc. here

        var $msgElement = $(element);
        var entity = viewModel;

        var propName = valueAccessor();
        if (propName === null) {
            //  $element.prev().data("bind") = "value: itemType"
            var prevBinds = $msgElement.prev().data("bind");
            if (!prevBinds) {
                $msgElement.text("Could not find prev elements binding value.");
                return;
            }
            var bindPhrases = prevBinds.split(/,/);
            for (var i = 0, j = bindPhrases.length; i < j; i++) {
                var bindPhrase = bindPhrases[i];
                if (utility.stringStartsWith(bindPhrase, 'value: ')) {
                    propName = bindPhrase.substr(7);
                    break;
                }
            }
        }

        if (!propName) {
            $msgElement.text("Could not find this or prev elements binding value.");
            return;
        }

        //var $groupElement = $msgElement.parent();      
        var $groupElement = $msgElement.closest(".control-group");
        if (!$groupElement.hasClass("control-group")) {
            $msgElement.text("Could not find parent with 'control-group' class.");
            return;
        }


        onValidationChange();               //fire immediately (especially for added)
                                            //... and anytime validationErrors are changed fire onValidationChnange
        entity.entityAspect.validationErrorsChanged.subscribe(onValidationChange);

        element.onchange = function () {
            //Should never have updates pushed from validation msgElement
            $msgElement.text("readonly error");
        };


        function onValidationChange() {
            var errors = entity.entityAspect.getValidationErrors(propName);
            var message = "";
            if (errors.length > 0) {
                message = errors[0].errorMessage;
            }

            if (message) {
                $groupElement.addClass('error');
            }
            else {
                $groupElement.removeClass('error');
            }

            $msgElement.text(message);
        }


    }
    //Not interested in changes to valueAccessor - it is only the fieldName.
    //update: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
};

例如查看简单隐式属性用法:

<div class="control-group">
    <label class="control-label" for="editStatusNote">Status note:</label>
    <div class="controls">
        <input id="editStatusNote" type="text" data-bind="value: statusNote" />
        <span class="help-inline" data-bind="breezeValidation: null"></span>
    </div>
</div>

例如查看显式属性用法:

<div class="control-group">
    <label class="control-label" for="editAmount">Amount:</label>
    <div class="controls">
        <div class="input-prepend">
            <span class="add-on">$</span>
            <input id="editAmount" class="input-small" type="text" data-bind="value: amount" />
        </div>
        <span class="help-inline" data-bind="breezeValidation: 'amount'"></span>
    </div>
</div>                        


Answer 5:

我更新breezeValidation来引导3,并与多径性支持改善。

ko.bindingHandlers.breezeValidation = {
    init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
        // This will be called when the binding is first applied to an element
        // Set up any initial state, event handlers, etc. here

        var $msgElement = $(element);
        var entity = viewModel;

        var propName = valueAccessor();
        if (propName === null) {
            //  $element.prev().data("bind") = "value: itemType"
            var prevBinds = $msgElement.prev().data("bind");
            if (!prevBinds) {
                $msgElement.text("Could not find prev elements binding value.");
                return;
            }
            var bindPhrases = prevBinds.split(/,/);
            for (var i = 0, j = bindPhrases.length; i < j; i++) {
                var bindPhrase = bindPhrases[i];
                if (bindPhrase.substr(0, 7) == 'value: ') {
                    propName = bindPhrase.substr(7);

                    entity = ko.utils.unwrapObservable(entity);
                    var propPath = propName.replace(/[()]/g, "").split('.'), i = 0;
                    var tempProp = entity[propPath[i]], links = propPath.length;
                    i++;
                    while (ko.utils.unwrapObservable(tempProp) && i < links) {
                        entity = ko.utils.unwrapObservable(tempProp);
                        tempProp = entity[propName = propPath[i]];
                        i++;
                    }

                    break;
                }
            }
        }

        if (!propName) {
            $msgElement.text("Could not find this or prev elements binding value.");
            return;
        }

        //var $groupElement = $msgElement.parent();      
        var $groupElement = $msgElement.closest(".form-group");
        if (!$groupElement.hasClass("form-group")) {
            $msgElement.text("Could not find parent with 'form-group' class.");
            return;
        }


        onValidationChange();               //fire immediately (especially for added)
        //... and anytime validationErrors are changed fire onValidationChnange
        entity.entityAspect.validationErrorsChanged.subscribe(onValidationChange);

        element.onchange = function () {
            //Should never have updates pushed from validation msgElement
            $msgElement.text("readonly error");
        };


        function onValidationChange() {
            var errors = entity.entityAspect.getValidationErrors(propName);
            var message = "";
            if (errors.length > 0) {
                message = errors[0].errorMessage;
            }

            if (message) {
                $groupElement.addClass('has-error');
            }
            else {
                $groupElement.removeClass('has-error');
            }

            $msgElement.text(message);
        }


    }
    //Not interested in changes to valueAccessor - it is only the fieldName.
    //update: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
};


Answer 6:

淘汰赛验证可以使用微风验证为一体:

function addKoValidationRules(entity) {
    if (entity.koValidationRulesAdded) {
        return;
    }
    entity.entityType.dataProperties.forEach(function (property) {
        entity[property.name].extend({
            validation: {
                validator: function () {
                    // manual validation ensures subscription to observables which current field depends on
                    // entity is added to context for retrieving other properties in custom validators
                    entity.entityAspect.validateProperty(property.name, { entity: entity });
                    var errors = entity.entityAspect.getValidationErrors(property.name);
                    if (!errors.length) {
                        return true;
                    }
                    this.message = errors[0].errorMessage;
                    return false;
                },
                message: ''
            }
        });
    });
    entity.koValidationRulesAdded = true;
}


文章来源: knockout validation using breeze utility?