【问题标题】:firing custom extender of one observable when another computed observable is changed当另一个计算的 observable 改变时触发一个 observable 的自定义扩展器
【发布时间】:2016-11-08 09:27:05
【问题描述】:

我正在尝试在不使用淘汰验证库的情况下创建自己的验证。我正在尝试创建一个通用的验证扩展器,它可以执行我希望它执行的所有类型的验证。我通过将对象中的验证类型和所需标志传递给扩展器来做到这一点。遇到的问题是 validate 方法仅在 Password 字段更改时触发,而不是在 PasswordVisible 属性更改时触发。当 Password 已经为空并且 PasswordVisible 属性发生更改时,这会导致问题,尝试清空 Password 不会被视为更改,因此不会触发扩展程序。

<!DOCTYPE html>

<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="utf-8" />
    <title></title>
</head>
<body>
    <script type="text/javascript" src="knockout-3.4.0.js"></script>

    Name:<input type="text" data-bind="value:Name" /><br />
    Already A User: <input type="checkbox" data-bind="checked:AlreadyUser" /><br />
    New Password:<input type="password" data-bind="value:Password,visible:PasswordVisible" /><br />
    <input type="button" value="Submit" onclick="validateModel();" />

    <script type="text/javascript" >
        var pageModel;

        ko.extenders.Validate = function (target, validateOptions) {
            target.HasErrors = ko.observable(false);
            var required = validateOptions.required();
            var validationType = validateOptions.validationType;
            function validate(newValue) {
                alert('validating');
                if (required) {
                    switch (validationType) {
                        case "Text":
                            target.HasErrors(newValue == "" ? false : true);
                            break;
                        default:
                            target.HasErrors(false);
                            break;
                    }
                }
            }

            validate(target());
            target.subscribe(validate);
            return target;
        };

        //The model itself
        var ViewModel = function () {            
            var self = this;
            self.Name = ko.observable('');
            self.AlreadyUser = ko.observable(false);
            //computed variable that sets the visibility of the password field. I have to clear the password when am making it invisible
            self.PasswordVisible = ko.computed(function () { return !this.AlreadyUser(); }, this).extend({ notify: 'always' });
            //this field is only required when visible
            self.Password = ko.observable('').extend({ Validate: { required: function () { return self.PasswordVisible() }, validationType: "Text" } });
            self.PasswordVisible.subscribe(function (newVal) { self.Password(''); });
            self.HasErrors = ko.computed(function () { return self.Password.HasErrors(); },self);
        };



        //The method calls on click of button
        function validateModel() {
            alert(pageModel.HasErrors());
            }

        //create new instance of model and bind to the page
        window.onload = function () {          
            pageModel = new ViewModel();
            ko.applyBindings(pageModel);
        };

    </script>
</body>
</html>

如何在 PasswordVisible 更改时触发验证。

【问题讨论】:

    标签: knockout.js knockout-validation


    【解决方案1】:

    您可以将 HasErrors 设为 ko.computed 以自动创建对任何使用的 observable 的订阅。不过,它可能会引发一些不必要的重新评估......

    ko.extenders.Validate = function(target, validateOptions) {
      target.HasErrors = ko.computed(function() {
        // Create subscription to newValue
        var newValue = target();
    
        // Create subscriptions to any obs. used in required
        var required = validateOptions.required();
        var validationType = validateOptions.validationType;
    
        if (ko.unwrap(required)) {
          switch (validationType) {
            case "Text":
              return newValue == "";
          }
        };
    
    
        return false;
      }, null, {
        deferEvaluation: true
      });
    
      return target;
    };
    

    请注意,您也不需要将 PasswordVisible 可观察对象包装在函数中来执行它;你可以改用ko.unwrap

    这是我在您的代码中的方法。当您隐藏密码时,如果里面有一个值(通过self.Password('') 清除会触发另一个验证),您可能想再看看多重验证。

    var pageModel;
    var i = 0;
    ko.extenders.Validate = function(target, validateOptions) {
      target.HasErrors = ko.computed(function() {
        console.log("validating " + ++i);
    
        // Create subscription to newValue
        var newValue = target();
    
        // Create subscriptions to any obs. used in required
        var required = validateOptions.required();
        var validationType = validateOptions.validationType;
    
        if (ko.unwrap(required)) {
          switch (validationType) {
            case "Text":
              return newValue == "";
          }
        };
    
    
        return false;
      }, null, {
        deferEvaluation: true
      });
    
      return target;
    };
    
    //The model itself
    var ViewModel = function() {
      var self = this;
      self.Name = ko.observable('');
      self.AlreadyUser = ko.observable(false);
      //computed variable that sets the visibility of the password field. I have to clear the password when am making it invisible
      self.PasswordVisible = ko.computed(function() {
        return !this.AlreadyUser();
      }, this).extend({
        notify: 'always'
      });
      //this field is only required when visible
      self.Password = ko.observable('').extend({
        Validate: {
          required: function() {
            return self.PasswordVisible()
          },
          validationType: "Text"
        }
      });
      self.PasswordVisible.subscribe(function(newVal) {
        self.Password('');
      });
      self.HasErrors = ko.computed(function() {
        return self.Password.HasErrors();
      }, self);
    };
    
    
    
    //The method calls on click of button
    function validateModel() {
      console.log(pageModel.HasErrors());
    }
    
    //create new instance of model and bind to the page
    window.onload = function() {
      pageModel = new ViewModel();
      ko.applyBindings(pageModel);
    };
    <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
    
    Name:
    <input type="text" data-bind="value:Name" />
    <br />Already A User:
    <input type="checkbox" data-bind="checked:AlreadyUser" />
    <br />New Password:
    <input type="password" data-bind="value:Password,visible:PasswordVisible" />
    <br />
    <input type="button" value="Submit" onclick="validateModel();" />

    【讨论】:

    • 您好,感谢您的回复。它工作正常。我同意。我会看看我怎样才能让它只开火一次。如果不是,我将在这里发布另一个问题.. 计算的 HasErrors 变量只有一个微不足道的更正,我需要返回 newValue == '' 而不是`!=。它。
    • 我已经通过添加延迟扩展解决了这个问题。如下extend({deferred: true})
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-03-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多