0

我偶然发现了一些具有 jQuery 验证的代码,该验证是在将项目添加到 DOM 的 ajax 调用之后触发的。验证正在运行,但消息丢失。只是该字段被突出显示。我已经玩了一段时间来让它工作,但到目前为止还没有运气。任何想法,想法表示赞赏。

 $('#add-other-income-link').click(function (event) {
    event.preventDefault();
    var otherIncomesCount = $('#numberOfNewOtherIncomes').val();
    $('div[hideCorner = yep]').show();

    var url = $(this).attr('href');
    if (url) {
        $.ajax({
            url: url,
            type: 'GET',
            dataType: 'html',
            success: function (data) {
                $('#additional-other-income').append(data);

                var count = otherIncomesCount;

                var id = 0;
                $('#additional-other-income').find('table.other-income-table').each(function (i, item) {
                    id = $(item).find('input.other-income-id');
                    var additionalIncomeTypeIdLabel = $(item).find('label.other-income-type-id-label');
                    var amountLabel = $(item).find('label.other-income-amount-label');
                    var additionalIncomeTypeIdMenu = $(item).find('select.other-income-type-id');
                    var amountTextBox = $(item).find('input.other-income-amount');

                    var idIndexer = 'OtherIncome_' + count + '__';
                    var nameIndexer = 'OtherIncome[' + count + '].';
                    var indexer = '[' + i + ']';
                    id.attr('id', idIndexer + 'Id').attr('name', nameIndexer + 'Id');
                    additionalIncomeTypeIdLabel.attr('for', idIndexer + 'AdditionalIncomeTypeId');
                    amountLabel.attr('for', idIndexer + 'Amount');
                    additionalIncomeTypeIdMenu.attr('id', idIndexer + 'AdditionalIncomeTypeId').attr('name', nameIndexer + 'AdditionalIncomeTypeId');
                    amountTextBox.attr('id', idIndexer + 'Amount').attr('name', nameIndexer + 'Amount').attr('data-val', 'true');

                    ++count;

                    addOtherIncomeValidation(item);
                });

对于 AdditionalIncomeTypeIDMenu 上的required和amountTextBox 上的 required 和 positive 验证均成功,但两者的消息均未显示

function addOtherIncomeValidation(container) {
if (container) {
    var additionalIncomeTypeIdMenu = $(container).find('select.other-income-type-id');
    var amountTextBox = $(container).find('input.other-income-amount');


    $(additionalIncomeTypeIdMenu).rules('add', {
        required: true,
        messages: {
            required: 'Please select an income type'
        }
    });

    $(amountTextBox).rules('add', {
        required: true,
        positive: true,
        messages: { positive: 'must be positive number'

        }
    });
}
}

顺便说一句,ajax 调用在此处返回部分 EditorTemplate,您可以看到它使用了 ValidationMessageFor。

<div class="other-income" style="margin-bottom: 10px;">
<table class="other-income-table">
    <tr>
        <td>
            @Html.HiddenFor(x => x.Id, new { @class = "other-income-id" })
            @Html.LabelFor(x => x.AdditionalIncomeTypeId, "Type:", new { @class = "other-income-type-id-label" })
            <br />@Html.ValidationMessageFor(x => x.AdditionalIncomeTypeId)
        </td>
        <td>
            @Html.LabelFor(x => x.Amount, "Amount:", new { @class = "other-income-amount-label" })
            <br />@Html.ValidationMessageFor(x => x.Amount)
        </td>
        <td>&nbsp;&nbsp;</td>
    </tr>
    <tr>
        <td>@Html.DropDownListFor(x => x.AdditionalIncomeTypeId, new SelectList(Model.AdditionalIncomeTypes, "Value", "Text", Model.AdditionalIncomeTypeId), "--- Select One ---", new { @class = "other-income-type-id" })</td>
        <td>
            @Html.EditorFor(x => x.Amount, "Money", new { AdditionalClasses = "other-income-amount" })
        </td>
        <td>
            @{
                int? otherIncomeId = null;
                var removeOtherIncomeLinkClasses = "remove-other-income-link";
                if (Model.Id == 0)
                {
                    removeOtherIncomeLinkClasses += " new-other-income";
                }
                else
                {
                    otherIncomeId = Model.Id;
                }
            }
            @Html.ActionLink("Remove", "RemoveOtherIncome", "Applicant", new { applicationId = Model.ApplicationId, otherIncomeId = otherIncomeId }, new { @class = removeOtherIncomeLinkClasses })<img class="hide spinner" src="@Url.Content("~/Content/Images/ajax-loader_16x16.gif")" alt="Deleting..." style="margin-left: 5px;" />
        </td>
    </tr>
</table>

HTML:

       <div id="OtherIncome" class="applicant-section">

<h2 class="header2">Other Income</h2>
<div class="cornerForm">

<div class="other-income" style="margin-bottom: 10px;">
    <table class="other-income-table">
        <tr>
            <td>
                <input class="other-income-id" data-val="true" data-val-number="The field Id must be a number." id="OtherIncome_0__Id" name="OtherIncome[0].Id" type="hidden" value="385" />
                <label class="other-income-type-id-label" for="OtherIncome_0__AdditionalIncomeTypeId">Type:</label>
                <br /><span class="field-validation-valid" data-valmsg-for="OtherIncome[0].AdditionalIncomeTypeId" data-valmsg-replace="true"></span>
            </td>
            <td>
                <label class="other-income-amount-label" for="OtherIncome_0__Amount">Amount:</label>
                <br /><span class="field-validation-valid" data-valmsg-for="OtherIncome[0].Amount" data-valmsg-replace="true"></span>
            </td>
            <td>&nbsp;&nbsp;</td>
        </tr>
        <tr>
            <td><select class="other-income-type-id" data-val="true" data-val-number="The field AdditionalIncomeTypeId must be a number." id="OtherIncome_0__AdditionalIncomeTypeId" name="OtherIncome[0].AdditionalIncomeTypeId"><option value="">--- Select One ---</option>
<option value="1">Alimony</option>
<option value="2">Child Support</option>
<option value="3">Disability</option>
<option value="4">Investments</option>
<option selected="selected" value="5">Rental Income</option>
<option value="6">Retirement</option>
<option value="7">Secondary Employment</option>
<option value="8">Separate Maintenance</option>
</select></td>
            <td>


<input class="money other-income-amount" data-val="true" data-val-number="The field Amount must be a number." id="OtherIncome_0__Amount" name="OtherIncome[0].Amount" style="" type="text" value="0.00" />
            </td>
            <td>
                <a class="remove-other-income-link" href="/Applicant/RemoveOtherIncome/XNxxxxx753/385">Remove</a><img class="hide spinner" src="/Content/Images/ajax-loader_16x16.gif" alt="Deleting..." style="margin-left: 5px;" />
            </td>
        </tr>
    </table>


</div>
<div class="other-income" style="margin-bottom: 10px;">
    <table class="other-income-table">
        <tr>
            <td>
                <input class="other-income-id" data-val="true" data-val-number="The field Id must be a number." id="OtherIncome_1__Id" name="OtherIncome[1].Id" type="hidden" value="412" />
                <label class="other-income-type-id-label" for="OtherIncome_1__AdditionalIncomeTypeId">Type:</label>
                <br /><span class="field-validation-valid" data-valmsg-for="OtherIncome[1].AdditionalIncomeTypeId" data-valmsg-replace="true"></span>
            </td>
            <td>
                <label class="other-income-amount-label" for="OtherIncome_1__Amount">Amount:</label>
                <br /><span class="field-validation-valid" data-valmsg-for="OtherIncome[1].Amount" data-valmsg-replace="true"></span>
            </td>
            <td>&nbsp;&nbsp;</td>
        </tr>
        <tr>
            <td><select class="other-income-type-id" data-val="true" data-val-number="The field AdditionalIncomeTypeId must be a number." id="OtherIncome_1__AdditionalIncomeTypeId" name="OtherIncome[1].AdditionalIncomeTypeId"><option value="">--- Select One ---</option>
<option selected="selected" value="1">Alimony</option>
<option value="2">Child Support</option>
<option value="3">Disability</option>
<option value="4">Investments</option>
<option value="5">Rental Income</option>
<option value="6">Retirement</option>
<option value="7">Secondary Employment</option>
<option value="8">Separate Maintenance</option>
</select></td>
            <td>


<input class="money other-income-amount" data-val="true" data-val-number="The field Amount must be a number." id="OtherIncome_1__Amount" name="OtherIncome[1].Amount" style="" type="text" value="22.00" />
            </td>
            <td>
                <a class="remove-other-income-link" href="/Applicant/RemoveOtherIncome/XN42093753/412">Remove</a><img class="hide spinner" src="/Content/Images/ajax-loader_16x16.gif" alt="Deleting..." style="margin-left: 5px;" />
            </td>
        </tr>
    </table>


</div>

    <div id="additional-other-income"></div>

    <input id="numberOfNewOtherIncomes" name="numberOfNewOtherIncomes" type="hidden" value="0" />
    <input data-val="true" data-val-number="The field OriginalOtherIncomeTotal must be a number." id="OriginalOtherIncomeTotal" name="OriginalOtherIncomeTotal" type="hidden" value="22.0000" />
    <a class="editable-link" href="/Applicant/AddOtherIncome?appId=XNxxxxx753" id="add-other-income-link">Add Other Income</a>
</div>        </div>

验证码:

$.validator.addMethod('positive', function(value, element) {
var check = true;
if (value < 0) {
    check = false;
}
return this.optional(element) || check;
}, "Value must be a positive number."
);
4

1 回答 1

1

I didn't think I would find my own answer but I did. first I have to apologize for my response to @Sparky with his request for rendered HTML. I did a "View page source" but that didn't include all the stuff which was added from the ajax call after the server delivered it's stuff. I suspect if I did include the extra DOM stuff at first, you would have pinpointed the issue sooner. My bad. Now on to the answer.

It appears that when injecting an EditorTemplate into the DOM in the way shown above, it doesn't properly process the page like you would expect in MVC. The code for @Html.ValidationMessageFor simply does not get parsed AT ALL. I am a little new to validation as you can see so I don't know why it behaves this way. To solve my problem here is what I did:

I updated my Editor Template slightly to look like this:

<div class="other-income" style="margin-bottom: 10px;">
<table class="other-income-table">
    <tr>
        <td>
            @Html.HiddenFor(x => x.Id, new { @class = "other-income-id" })
            @Html.LabelFor(x => x.AdditionalIncomeTypeId, "Type:", new { @class = "other-income-type-id-label" })
          <br />
            @Html.ValidationMessageFor(x=>x.AdditionalIncomeTypeId)
            <span id="AdditionalIncomeTypeIdValidation"></span>
        </td>
        <td>
            @Html.LabelFor(x => x.Amount, "Amount:", new { @class = "other-income-amount-label" })
            <br />
            @Html.ValidationMessageFor(x=>x.Amount)
            <span id="amountValidation"></span>
         </td>
        <td>&nbsp;&nbsp;</td>
    </tr>
    <tr>
        <td>@Html.DropDownListFor(x => x.AdditionalIncomeTypeId, new SelectList(Model.AdditionalIncomeTypes, "Value", "Text", Model.AdditionalIncomeTypeId), "--- Select One ---", new { @class = "other-income-type-id" })</td>
        <td>
            @Html.EditorFor(x => x.Amount, "Money", new { AdditionalClasses = "other-income-amount" })
        </td>
        <td>
            @{
                int? otherIncomeId = null;
                var removeOtherIncomeLinkClasses = "remove-other-income-link";
                if (Model.Id == 0)
                {
                    removeOtherIncomeLinkClasses += " new-other-income";
                }
                else
                {
                    otherIncomeId = Model.Id;
                }
            }
            @Html.ActionLink("Remove", "RemoveOtherIncome", "Applicant", new { applicationId = Model.ApplicationId, otherIncomeId = otherIncomeId }, new { @class = removeOtherIncomeLinkClasses })<img class="hide spinner" src="@Url.Content("~/Content/Images/ajax-loader_16x16.gif")" alt="Deleting..." style="margin-left: 5px;" />
        </td>
    </tr>
</table>

Notice the new span tags, which is are added next to the @Html.ValidationMessageFor.

then in my success function from the ajax call in javascript I made these changes:

  $('#add-other-income-link').click(function (event) {
        event.preventDefault();
        var count = $('#numberOfNewOtherIncomes').val();
        $('div[hideCorner = yep]').show();

        var url = $(this).attr('href');
        if (url) {
            $.ajax({
                url: url,
                type: 'GET',
                dataType: 'html',
                success: function (data) {
                    $('#additional-other-income').append(data);

                    var id = 0;
                    $('#additional-other-income').find('table.other-income-table').each(function (i, item) {
                        id = $(item).find('input.other-income-id');
                        var additionalIncomeTypeIdLabel = $(item).find('label.other-income-type-id-label');

                        var amountLabel = $(item).find('label.other-income-amount-label');
                        var additionalIncomeTypeIdMenu = $(item).find('select.other-income-type-id');
                        var amountTextBox = $(item).find('input.other-income-amount');
                        var amountValidation = $(item).find('#amountValidation');
                        var typeIdValidation = $(item).find('#AdditionalIncomeTypeIdValidation');

                        var idIndexer = 'OtherIncome_' + count + '__';
                        var nameIndexer = 'OtherIncome[' + count + '].';
                        var indexer = '[' + i + ']';
                        amountValidation.attr('class', 'field-validation-valid')
                                        .attr('data-valmsg-for', nameIndexer + 'Amount')
                                        .attr('data-valmsg-replace','true');
                        typeIdValidation.attr('class', 'field-validation-valid')
                                        .attr('data-valmsg-for', nameIndexer + 'AdditionalIncomeTypeId')
                                        .attr('data-valmsg-replace','true');
                        id.attr('id', idIndexer + 'Id').attr('name', nameIndexer + 'Id');
                        additionalIncomeTypeIdLabel.attr('for', idIndexer + 'AdditionalIncomeTypeId');
                        amountLabel.attr('for', idIndexer + 'Amount');
                        additionalIncomeTypeIdMenu.attr('id', idIndexer + 'AdditionalIncomeTypeId').attr('name', nameIndexer + 'AdditionalIncomeTypeId');
                        amountTextBox.attr('id', idIndexer + 'Amount').attr('name', nameIndexer + 'Amount').attr('data-val', 'true');


                        ++count;

                        addOtherIncomeValidation(item);

notice I am manually adding in the missing validation spans that were not rendering. Now the validation message shows up at validation! Yay. I am not sure however that this is the best fix. It looks and smells like a hack, but I got it to work. I am sure it can be done a better way. Thanks again for interaction and feedback.

于 2013-04-19T16:51:52.073 回答