如何通过客户端验证要求数组至少有一个项目?

How can I require an array to have at least one item by means of client-side validation?

我有一个表单,用户可以在其中通过文本区域输入问题。通过点击一个按钮,他可以动态地生成更多的文本字段来输入问题。我将 Knockout 与问题绑定到的客户端视图模型一起使用。

我的简化视图(Razor)如下:

<div data-bind="foreach: openQuestions">
    <div class="form-group">
        <input type="hidden" data-bind="value: currentIndex" name="openQuestions.Index" />
        <textarea class="form-control" rows="3" data-bind="value: question, attr: { name: 'openQuestions[' + $data.currentIndex + '].Question' }"/>
    </div>
</div>
@Html.ValidationMessageFor(m => m.OpenQuestions)

Knockout VM 的一部分:

function OpenQuestion() {
    var self = this;

    self.currentIndex = GetRandomIndex();
    self.question = ko.observable();
}

function QuestionViewModel() {
    var self = this;
    self.openQuestions = ko.observableArray();

    self.addOpenQuestion = function () {
        self.openQuestions.push(new OpenQuestion());
    }
}

应该进行两次验证:

  1. 'OpenQuestions' 列表不应为空(因此 != null 且 >= 1 个条目)
  2. 上述列表中的每个问题都不能为空或为空

我很难连接 jQuery 验证器来验证数组的最小长度。我认为问题在于加载页面时,没有名称为 'OpenQuestions' 的元素,因为还没有问题。如果您此时提交,验证器找不到任何要验证的元素,并简单地假设所有内容都有效,但事实并非如此。

我尝试创建自定义 "minimum length array required" 验证属性,但我 运行 遇到了同样的问题 - 你将它连接到哪个元素?

基本上,此方法会检查它是否可以找到与提供的名称类似的任何元素(例如 'openquestions',但 'openquestions[123456]' 也可以)并将该长度与所需的最小长度进行比较。

$.validator.addMethod("minarraylength",
    function (value, element, parameters) {
            var minLength = parameters["minlength"];

            if (element) {
                var elementName = $(element).attr("name").toLowerCase();

                var actualLength = $("input").filter(function () {
                    var currentName = $(this).attr("name");
                    return currentName != undefined && currentName.toLowerCase().indexOf(elementName);
                }).length;

                return actualLength >= minLength;
        }

        return true;
    }
);

像这样将其与隐藏字段组合

@Html.HiddenFor(m => m.OpenQuestions)

将触发验证,但会导致模型绑定器在提交时失败,因为出于某种原因它会从隐藏字段中取出值并忽略其他所有内容。

所以问题是,如何将 jQuery 验证器连接到我动态生成的列表中,确保模型绑定在回发时有效,但防止提交空列表?

提前致谢!

您可以简单地扩展您的 KO 对象,见下文:

第 1 步:为至少 1 个要求的数组创建自定义 KO 规则

ko.validation.rules["atLeastOne"] = {
    validator: function(value, validate) {
        if (validate && Array.isArray(value)) {
            return !!value.length;
        }
        return true;
    },
    message: "Please add at least one."
};

第 2 步更新您的代码:

function OpenQuestion() {
    var self = this;

    self.currentIndex = GetRandomIndex();
    self.question = ko.observable().extend({
       required: true,
       minLength: 1
    });
}

function QuestionViewModel() {
    var self = this;
    self.openQuestions = ko.observableArray().extend({
        atLeastOne: {
            message: "Please add at least one."
        }
    });

    self.addOpenQuestion = function () {
        self.openQuestions.push(new OpenQuestion());
    }
}