如何将 ko.validation 错误与相关的视图模型字段名称联系在一起

Posted

技术标签:

【中文标题】如何将 ko.validation 错误与相关的视图模型字段名称联系在一起【英文标题】:How to tie together ko.validation errors with related viewmodel field names 【发布时间】:2013-08-10 08:45:07 【问题描述】:

我正在使用 Knockout.Validation 并且我希望能够显示错误摘要,其中每一行都显示错误消息(显然!)以及与之相关的视图模型上的字段名称,例如

年龄 - 请输入数字 出生日期 - 请输入正确的日期

到目前为止,我已经有一个经过验证的Observable 包装了我的视图模型,这会自动在我的视图模型上放置一个错误数组,其中包含我的所有错误。但是我看不到任何简单的方法来检索每个错误与哪个字段相关。

我知道我可以自己遍历视图模型,从 isValid 属性建立我自己的错误集合 - 这是我唯一的选择吗?

获得字段名称后,我可以将验证摘要映射到该字段的相关“友好”标签(例如“出生日期”而不是“出生日期”)。

这是我目前所拥有的代码的简化版本:

视图模型

function PersonModel()
   var self = this;
   self.Age = ko.observable().extend( number: true);

   self.DateOfBirth = ko.observable( date: true);             
   self.Validate = function()                            
       if (!self.isValid())                                          
          self.errors.showAllMessages();        
          return false;          
       
       return true;
    ;    

ko.validation.init(
                grouping:  deep: true, observable: true ,
                registerExtenders: true,
                messagesOnModified: true,
                insertMessages: true
            );

ko.applyBindings(ko.validatedObservable(new PersonModel()));

html

<ul data-bind='foreach: model().errors' class="message">
    <li>
           <span data-bind='text:  $data'></span>
    </li>
</ul>

非常感谢

【问题讨论】:

可以分享一下你目前掌握的相关代码吗? 【参考方案1】:

您可以对任何变量使用自定义验证消息。

emailAddress: ko.observable().extend(
    required:  message: 'Email Address: Required field.' 
),

【讨论】:

当你有两个相同的东西被验证时,这就会崩溃 - 例如,账单和送货地址都有相同的字段 它们不应该是相同的可观察对象,淘汰赛验证要求您扩展每个个体(可观察对象),这将被验证。您可以对邮政地址使用 onlyif 验证规则或其他一些自定义规则 github.com/Knockout-Contrib/Knockout-Validation/wiki/…。【参考方案2】:

您可以执行以下操作:

添加一个 friendlyName 扩展器,为您的 observables 提供一个友好的名称 破解显示消息的绑定处理程序

好听的名字:

有史以来最简单的淘汰赛延长器:

ko.extenders.friendlyName = function (obs, options) 
    obs.friendlyName = options;

用法:self.Age = ko.observable(3).extend( friendlyName: "My Age" );

显示消息破解:

敲除验证插件创建一个绑定处理程序validationMessage 来显示错误消息。您可以直接使用它(带有一些 html 标记)或让插件使用配置选项 insertMessages 处理消息。

这里我只是编辑它创建的 html(仍然调用原始绑定处理程序)以考虑 friendlyName

var originalValidationMessageUpdate= ko.bindingHandlers.validationMessage.update;
ko.bindingHandlers.validationMessage.update = 
    function (element, valueAccessor, allBindingAccessor, viewModel, 
              bindingContext) 
        if (originalValidationMessageUpdate)
            originalValidationMessageUpdate(element, valueAccessor, 
                                            allBindingAccessor, viewModel,
                                            bindingContext);
        var prepend = (ko.isObservable(valueAccessor()) 
                            && valueAccessor().friendlyName)
                                  ? valueAccessor().friendlyName + " - "
                                  : "";

        $(element).html(prepend + $(element).html());
        // ^^^^ This is the line that is actually useful
    

注意:我没有将friendlyName 创建为可观察对象,因为我猜它不会被更新,但可以这样做。

Demo

【讨论】:

我会接受这个想法,谢谢。很遗憾,他们不能在 Ko.Validation 中加入一些东西来提供帮助 - 可能会建议! @philicomus 好吧,你可以contribute :)【参考方案3】:

我发现这很好用 - 在控制台中输入 (F12):

for(var propertyName in PersonModel()) 
  console.log(ko.validation.group(PersonModel()[propertyName])())

这会给你类似的东西:

[]
[]
[]
[This field is required.]
[]
[]

然后,您可以将问题字段绑定到模型中的属性。 在本例中,问题出在第 4 个属性上。

我希望这对某人有所帮助。

【讨论】:

丑陋,但有效,什么是淘汰赛验证没有经过验证的 observable 的名称?【参考方案4】:

很遗憾,您需要为每个验证器指定消息,除非您按照 GôTô 的建议执行完全自定义的操作。

想一想……您还没有为您的字段指定显示名称,那么 ko 验证应该如何知道验证错误消息的字段名称?

最简单的方法:

self.Age = ko.observable().extend( 
   number: 
      params: true,
      message: 'Age - please enter a number'
   ,
   required:  
      params: true,
      message: 'Age is required'
   
);

如果这样做是合理的,您可能需要投资于扩展默认消息传递行为,否则为每个属性上的每个验证器指定消息会更容易。

【讨论】:

我认为这确实适用于简单的视图模型,其中字段是静态的,但我实际上正在编写一个框架,其中包含各种字段的元数据,包括显示/友好名称。因此,我确实需要在框架级别上基于此元数据将 ko.extenders 应用于我的(动态)对象,并且为避免重复,这需要尽可能通用。因此,我可能会根据 GôTô 的想法选择一些东西,但还会将友好名称添加到错误集合中。 @philicomus 您最初的问题是差不多一年前的 - 您在此期间在做什么? 服务器验证一件事! :) 我将服务器上的验证视为最高优先级,并将附加的客户端验证视为一项不错的选择。由于这是我一直在开发的框架,因此我一直致力于使用该框架实现新应用程序。【参考方案5】:

这种开销最小的方法非常适合我的需求:

ko.validation.rules["required"].message = "0 required";

用法:

self.driverName = ko.observable().extend( required: "Driver Name" );

渲染结果:

Driver Name required

注意:单步执行 knockout.validation.js 向我展示了将默认的 ko.validation.rules[] PRIOR 修改为任何 ko.observable().extend() 调用至关重要。

【讨论】:

【参考方案6】:

虽然这不能回答这个问题的“友好”标签部分,也不会导致一系列验证错误,但它确实构建了一个对象,让您可以看到巨大的视图模型验证错误隐藏在哪里。这个问题提到了遍历视图模型来构建错误,所以我想我会在 Lodash 的帮助下分享我为此构建的递归函数。

function getErrors(koVm, maxDepth, currentDepth) 
    if ((currentDepth || 0) < (maxDepth || 5)) 
        var obj = _.pickBy(_.mapValues(koVm, function(value) 
            if (value) 
                if (_.isFunction(value.error)) 
                    return value.error();
                

                return getErrors(value, maxDepth, (currentDepth || 0) + 1);
            

            return null;
        ));

        return _.keysIn(obj).length ? obj : null;
    

    return null;

它不适合向用户显示错误(除非您将构造的对象展平),但在调试和尝试找出大型模型的哪些部分无效时,它很有帮助。

【讨论】:

以上是关于如何将 ko.validation 错误与相关的视图模型字段名称联系在一起的主要内容,如果未能解决你的问题,请参考以下文章

KnockOut.js 验证始终为真/errors.length = 0

insertValidationMessage 敲除不起作用

存储过程是不是可以调用截断 veiw 表并将数据输入到 MySql 中的视图表中[关闭]

超强兼容性与扩展能力的视壮rk3399,VR游戏盒子热用

GB/T28181-2016基于RTP的视音频数据封装和技术实现

实时监控视频与超图GIS的对接应用(实时视频的介绍)