You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于ASP.NET MVC、C#、KnockoutJS的指定文本框错误高亮问题

ASP.NET MVC + KnockoutJS: Show Validation Errors Next to Dynamic Textareas

Got it, let's fix this so each textarea shows its own error message instead of a global one. Here's a step-by-step solution tailored to your code:

1. Update the Record Structure in Knockout ViewModel

First, we need each dynamic record to track its own error state. Modify your view model to add an error observable to every record:

(function () {
  var viewModel = function (vmData) {
    var self = this;
    self.errorFlag = ko.observable(false);
    self.errorText = ko.observable();
    self.records = ko.observableArray();
    
    // Initialize records with input AND error observables
    self.records([{ 
      input: ko.observable(""), 
      error: ko.observable("") 
    }]);
    
    self.addRecord = function () {
      self.records.push({ 
        input: ko.observable(""), 
        error: ko.observable("") 
      });
    };

    // ... rest of the code will be updated next
  }
  var pageVM = new viewModel();
  ko.applyBindings(pageVM, $("form")[0]);
})();

2. Modify the HTML to Bind Per-Record Errors

Update your textarea and error span to bind to the current record's error observable. We'll also add conditional styling for invalid inputs:

<div data-bind="foreach: { data: records }">
  <div class="form-group">
    <div class="col-md-6 ">
      <textarea rows="1" 
                class="required form-control textbox-wide" 
                data-bind="value: input, 
                           attr: { name: 'Records[' + $index() + '].Input', id: 'Records[' + $index() + '].Input'},
                           css: { 'text-danger': error().length > 0 }"></textarea>
      <!-- Bind error text and visibility to the record's error -->
      <span class="help-block-msg text-danger" 
            data-bind="text: error, 
                       visible: error().length > 0"></span>
    </div>
    <div class="col-md-2">
      <input type="button" value="Add Record" class="btn btn-primary" 
             data-bind="click: $parent.addRecord, 
                        visible: $index() === $parent.records().length - 1" />
    </div>
  </div>
</div>

(Note: I simplified the visible binding for the Add button to make it cleaner.)

3. Update the MVC Controller to Return Per-Record Errors

Instead of returning a single error string, we'll return a list of errors tied to each input's index. First, create a simple model to deserialize the input:

public class RecordInput
{
    public string Input { get; set; }
}

Then modify your CheckRecord action to validate each input and return indexed errors:

using Newtonsoft.Json; // Make sure you have this NuGet package installed

[HttpPost]
public IActionResult CheckRecord(string input)
{
    var records = JsonConvert.DeserializeObject<List<RecordInput>>(input);
    var validationResults = new List<object>();

    for (int i = 0; i < records.Count; i++)
    {
        string errorMessage = string.Empty;
        
        // Replace this with your actual validation logic
        if (string.IsNullOrWhiteSpace(records[i].Input))
        {
            errorMessage = "Input cannot be empty";
        }
        else if (records[i].Input.Length < 3)
        {
            errorMessage = "Input must be at least 3 characters long";
        }

        validationResults.Add(new { Index = i, Error = errorMessage });
    }

    return Json(validationResults);
}

4. Update the Knockout checkInput Method to Handle Per-Record Errors

Modify the AJAX success handler to map the controller's validation results to the correct record's error observable:

self.checkInput = function () {
    // Convert observables to plain objects for serialization
    var recordsToValidate = self.records().map(function(record) {
        return { input: record.input() };
    });
    var inputJson = JSON.stringify(recordsToValidate);

    // Use async: true (sync is bad practice - blocks the browser)
    $.ajax({
        type: "POST",
        async: true,
        url:"/Home/CheckRecord",
        contentType: 'application/x-www-form-urlencoded; charset=utf-8',
        data: { "input": inputJson },
        success: function (validationResults) {
            // Clear all existing errors first
            self.records().forEach(function(record) {
                record.error("");
            });

            var isAllValid = true;
            // Map errors to the correct record
            validationResults.forEach(function(result) {
                if (result.Error) {
                    self.records()[result.Index].error(result.Error);
                    isAllValid = false;
                }
            });

            // Update global error state if needed
            self.errorFlag(!isAllValid);
            self.errorText(isAllValid ? 'All inputs are correct' : 'Some inputs have errors');
        }
    });
}

Key Improvements Explained

  • Per-record error tracking: Each textarea now has its own error observable, so errors are isolated to the input that caused them.
  • Targeted error display: The error span only shows when the corresponding input has an error, and the textarea gets a red style when invalid.
  • Scalable validation: The controller now validates each input individually, making it easy to add more validation rules later.
  • Better user experience: Async AJAX prevents blocking the browser while validating.

内容的提问来源于stack exchange,提问作者aman

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 08:27:33