【问题标题】:Validation not working on cloned elements验证不适用于克隆的元素
【发布时间】:2021-12-12 07:24:35
【问题描述】:

如果我创建多个这样的元素...

@for (int i = 0; i < 10; i++)
{
    <div class="row">
        <div class="col-md-6">
            <div class="form-group">
                <label asp-for="Railcars[i].RailcarNumber" class="control-label"></label>
                <input asp-for="Railcars[i].RailcarNumber" class="form-control" />
                <span asp-validation-for="Railcars[i].RailcarNumber" class="text-danger"></span>
            </div>
        </div>
        <div class="col-md-6">
            <div class="form-group">
                <label asp-for="Railcars[i].Weight" class="control-label"></label>
                <input asp-for="Railcars[i].Weight" class="form-control" />
                <span asp-validation-for="Railcars[i].Weight" class="text-danger"></span>
            </div>
        </div>
    </div>
}

验证似乎适用于所有行。

但是,如果我像这样创建单行...

<div class="railcars">
    <div class="row">
        <div class="col-md-6">
            <div class="form-group">
                <label asp-for="Railcars[0].RailcarNumber" class="control-label"></label>
                <input asp-for="Railcars[0].RailcarNumber" class="form-control" />
                <span asp-validation-for="Railcars[0].RailcarNumber" class="text-danger"></span>
            </div>
        </div>
        <div class="col-md-6">
            <div class="form-group">
                <label asp-for="Railcars[0].Weight" class="control-label"></label>
                <input asp-for="Railcars[0].Weight" class="form-control" />
                <span asp-validation-for="Railcars[0].Weight" class="text-danger"></span>
            </div>
        </div>
    </div>
</div>

然后使用 jQuery 的 clone() 克隆行,验证似乎只适用于第一(非克隆)行。

注意:我注意更新克隆元素的所有 IDnamefor 属性,并更新下标数字。我检查了它是否正确并将正确的信息发布到服务器。 ModelState 甚至可以正确检测克隆元素的验证问题。只是客户端验证对它们不起作用。

这是生成的 HTML:

未克隆的行(验证有效):

<div class="row first-railcar">
    <div class="col-md-4">
        <div class="form-group railcar-number">
            <label class="control-label" for="Railcars_0__Railcar">Railcar Number</label>
            <input class="form-control" type="text" data-val="true" data-val-length="The field Railcar Number must be a string with a maximum length of 18." data-val-length-max="18" data-val-required="The Railcar Number field is required." id="Railcars_0__Railcar" maxlength="18" name="Railcars[0].Railcar" value="">
            <span class="text-danger field-validation-valid" data-valmsg-for="Railcars[0].Railcar" data-valmsg-replace="true"></span>
        </div>
    </div>
    <div class="col-md-4">
        <div class="form-group railcar-volume">
            <label class="control-label" for="Railcars_0__Volume">Volume (pounds)</label>
            <input class="form-control" type="text" data-val="true" data-val-number="The field Volume (pounds) must be a number." data-val-required="The Volume (pounds) field is required." id="Railcars_0__Volume" name="Railcars[0].Volume" value="">
            <span class="text-danger field-validation-valid" data-valmsg-for="Railcars[0].Volume" data-valmsg-replace="true"></span>
        </div>
    </div>
    <div class="col-md-4">
        <div class="form-group">
            <label class="control-label">&nbsp;</label><br>
            <img class="add-railcar" src="/images/add.png" title="Add Additional Railcar" style="display: none;">
            <img class="remove-railcar" src="/images/delete_2.png" title="Remove Railcar" style="display: none">
        </div>
    </div>
</div>

克隆行(验证不起作用):

<div class="row">
    <div class="col-md-4">
        <div class="form-group railcar-number">
            <label class="control-label" for="Railcars_1__Railcar">Railcar Number</label>
            <input class="form-control" type="text" data-val="true" data-val-length="The field Railcar Number must be a string with a maximum length of 18." data-val-length-max="18" data-val-required="The Railcar Number field is required." id="Railcars_1__Railcar" maxlength="18" name="Railcars[1].Railcar" value="">
            <span class="text-danger field-validation-valid" data-valmsg-for="Railcars[1].Railcar" data-valmsg-replace="true"></span>
        </div>
    </div>
    <div class="col-md-4">
        <div class="form-group railcar-volume">
            <label class="control-label" for="Railcars_1__Volume">Volume (pounds)</label>
            <input class="form-control" type="text" data-val="true" data-val-number="The field Volume (pounds) must be a number." data-val-required="The Volume (pounds) field is required." id="Railcars_1__Volume" name="Railcars[1].Volume" value="">
            <span class="text-danger field-validation-valid" data-valmsg-for="Railcars[1].Volume" data-valmsg-replace="true"></span>
        </div>
    </div>
    <div class="col-md-4">
        <div class="form-group">
            <label class="control-label">&nbsp;</label><br>
            <img class="add-railcar" src="/images/add.png" title="Add Additional Railcar">
            <img class="remove-railcar" src="/images/delete_2.png" title="Remove Railcar" style="">
        </div>
    </div>
</div>

我还仔细地将上面克隆的 HTML 与我的第一个示例创建的 HTML(使用 for 循环)进行了比较,它们是相同的。显然,在页面加载后添加它有一些不同。

有谁知道如何以这种方式克隆元素并对所有克隆的元素进行验证工作?

更新:

我对 jQuery 的 clone() 的使用包括两个真值 ($row.clone(true, true))。如果我不这样做,我的图片的点击处理程序将不起作用。

按照建议,我在克隆元素后尝试了以下代码的几种变体。但我无法让它产生任何影响。

var form = document.getElementById('input-form');
$.validator.unobtrusive.parse(form);

【问题讨论】:

  • 我的猜测是,很可能有一个脚本在加载时在原始代码上运行,它允许验证属性被识别并按预期运行。这对我来说意味着当您在事后克隆元素时,负责管理验证的脚本不会添加或知道它们。我建议检查哪些脚本/函数在加载时运行,并查看哪些脚本/函数负责处理验证,并确保在完成克隆后调用它。
  • jQuery clone() 方法(不带参数)不保留客户端验证所依赖的自定义数据和事件(例如输入更改绑定)。试试clone(true),它会保留这些东西。另外,请参见此处:docs.microsoft.com/en-us/aspnet/core/mvc/models/…
  • @Evk:我正在使用clone(true, true)。否则,我的两个图像的点击处理程序不起作用。
  • 那么如果克隆 (true, true) 没有帮助 - 我会尝试上面链接中的方法 ($.validator.unobtrusive.parse())
  • @Evk:我不确定你是从哪里得到的或者它是如何工作的,但是在克隆一个元素后运行$.validator.unobtrusive.parse(); 不会改变行为。我想我不太了解 ASP.NET Core 客户端验证的内部工作原理。我同意,如果有某种初始化,那么我需要在克隆元素后重新运行它。

标签: c# jquery asp.net asp.net-core razor-pages


【解决方案1】:

您与$.validator.unobtrusive.parse(form); 走在正确的轨道上。但是,要让 jQuery Validation 处理复制/附加的 ajax/克隆元素,您需要三件事。

  • 确保每个输入元素都有唯一的名称。
  • 以现有元素的形式删除任何以前的验证绑定。
  • 重新创建验证绑定。

下面是一个工作示例。

<form>

    <div class="container" id="ElementContainer">

        <div id="ElementToClone">

            <div class="row">
                <div class="col col-md-4">
                    <div class="form-group">

                        <input class="form-control" type="text" name="elem[0]" id="elem_0" data-val="true" data-val-required="Required.">

                    </div>
                </div>
            </div>

        </div>

    </div>

    <div class="pt-3">
        <button type="button" class="btn btn-primary" onclick="Clone()">Clone</button>
        <button type="submit" class="btn btn-primary ml-3">Submit</button>
    </div>

</form>

<script>
    function Clone() {
        var $container = $('#ElementContainer');
        var $elem = $('#ElementToClone');
        var $form = $container.closest('form');

        //duplicate x times
        for (var i = 1; i <= 5; i++) {
            var clonedHtml = $elem.html();

            //create a unique name
            clonedHtml = clonedHtml.replace('elem[0]', 'elem[' + i + ']');

            //create an unique id (not required for validate to function)
            clonedHtml = clonedHtml.replace('elem_0', 'elem_' + i);

            //append the cloned element
            $container.append(clonedHtml);
        }

        //remove validation from the inital input elements or it won't work
        $form.removeData('validator').removeData('unobtrusiveValidation');

        //bind the validation again
        $.validator.unobtrusive.parse($form);
    }
</script>

附:在 MVC 上测试,而不是 Core。但它应该是一样的,因为它无论如何都是前端的。

【讨论】:

  • 并确保每个name 属性都是唯一的。所以甚至不是多个Railcars[1].Volume,而是Railcars[1], Railcars[2]等。
  • removeData() 的两次调用似乎起到了重要作用。没有这些行,它就行不通。有了他们,它确实如此。
猜你喜欢
  • 2016-12-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多