如何为条件要求 属性 实施客户端验证 - Razor ASP.NET 核心

How to implement client side validation for a conditional required property - Razor ASP.NET core

我有一个在两个页面(安全日志、失物招领处)之间共享的模型。我希望仅当 属性、'AppType' =“安全日志”时才需要 属性、'Narrative'。

我的服务器端验证工作正常,但是当我去保存表单时,表单上的下拉值丢失了它们的值,因为我使用的是 ViewBag。这是我目前拥有的。

SecurityLog.cs

public string AppType { get; set; }
[RequiredIf(nameof(AppType), "Security Log", ErrorMessage = "Narrative is required")]
public string Narrative { get; set; }

public class RequiredIfAttribute : ValidationAttribute
    {
        public string PropertyName { get; set; }
        public object Value { get; set; }

        public RequiredIfAttribute(string propertyName, object value, string errorMessage = "")
        {
            PropertyName = propertyName;
            ErrorMessage = errorMessage;
            Value = value;
        }

        protected override ValidationResult IsValid(object value, ValidationContext validationContext)
        {
            var instance = validationContext.ObjectInstance;
            var type = instance.GetType();
            var proprtyvalue = type.GetProperty(PropertyName).GetValue(instance, null);
            if (proprtyvalue.ToString() == Value.ToString() && value == null)
            {
                return new ValidationResult(ErrorMessage);
            }
            return ValidationResult.Success;
        }
    }

有谁知道如何在我的安全日志创建页面上实施客户端验证 (javascript/jquery/etc..)?我发现我的项目的其余必填字段会验证客户端,因为保留了下拉值。当我填写了 Narrative 以外的所有必填字段并单击保存后,我丢失了 dd 值,所以我知道这是在服务器端处理的。

点击保存前创建页面的示例

点击保存后创建页面的示例

创建页面逻辑

<div class="form-group">
    <label asp-for="SecurityLog.EntityID" class="control-label"></label>
    <select id="entity" asp-for="SecurityLog.EntityID" class="form-control" asp-items="ViewBag.EntityID">
         <option value="">--Select Entity--</option>
    </select>
    <span asp-validation-for="SecurityLog.EntityID" class="text-danger"></span>
</div>
<div class="form-group">
    <label asp-for="SecurityLog.LocationID" class="control-label"></label>
    <select id="location" asp-for="SecurityLog.LocationID" class="form-control"
            asp-items="ViewBag.LocationID">
        <option value="">--Select Location--</option>
    </select>
    <span asp-validation-for="SecurityLog.LocationID" class="text-danger"></span>
</div>
<div class="form-group">
    <label asp-for="SecurityLog.ShiftRangeID" class="control-label"></label>
    <select asp-for="SecurityLog.ShiftRangeID" class="form-control" asp-items="ViewBag.ShiftRangeID">
        <option value="">--Select Shift--</option>
    </select>
    <span asp-validation-for="SecurityLog.ShiftRangeID" class="text-danger"></span>
</div>
<div class="form-group">
    <label asp-for="SecurityLog.EventStart" class="control-label"></label>
    <input asp-for="SecurityLog.EventStart" class="form-control" id="datepicker2" type="text" autocomplete="off" />
    <span asp-validation-for="SecurityLog.EventStart" class="text-danger"></span>
</div>
<div class="form-group">
    <label asp-for="SecurityLog.EventEnd" class="control-label"></label>
    <input asp-for="SecurityLog.EventEnd" class="form-control" id="datepicker3" type="text" autocomplete="off" />
    <span asp-validation-for="SecurityLog.EventEnd" class="text-danger"></span>
</div>
<div class="form-group">
    <label asp-for="SecurityLog.ContactName" class="control-label"></label>
    <input asp-for="SecurityLog.ContactName" class="form-control" autocomplete="off" />
    <span asp-validation-for="SecurityLog.ContactName" class="text-danger"></span>
</div>
<div class="form-group">
    <label asp-for="SecurityLog.EventTypeID" class="control-label"></label>
    <select id="selectEventType" asp-for="SecurityLog.EventTypeID" class="form-control" asp-items="ViewBag.EventTypeID">
        <option value="">--Select Event Type--</option>
    </select>
    <span asp-validation-for="SecurityLog.EventTypeID" class="text-danger"></span>
</div>
<div class="form-group">
    <label asp-for="SecurityLog.Narrative" class="control-label"></label>
    <textarea asp-for="SecurityLog.Narrative" class="form-control" style="height:200px;"></textarea>
    <span asp-validation-for="SecurityLog.Narrative" class="text-danger"></span>
</div>    
<div class="form-group">
    <input type="submit" value="Create" class="btn btn-primary" id="btnCreateLog" onclick="return lockedOrNot()" />
</div>

Create.cshtml.cs

[BindProperty]
public SecurityLog SecurityLog { get; set; }
[BindProperty(SupportsGet = true)]
public int entity { get; set; }    

SelectList FilteredLocation;

public JsonResult OnGetLocations()
{

    FilteredLocation = new SelectList(_context.Location.Where(c => c.EntityID == entity).Where(c =>c.Active == "Y").OrderBy(c =>c.Name), "ID", "Name");
    
    return new JsonResult(FilteredLocation);
}


public IActionResult OnGetAsync()
{  
    ViewData["EntityID"] = new SelectList(_context.Entity.Where(a => a.Active == "Y").OrderBy(a => a.Name), "ID", "Name");                          
    ViewData["ShiftRangeID"] = new SelectList(_context.ShiftRange.Where(a=>a.Active == "Y").OrderBy(a => a.Name), "ID", "Name");
    ViewData["LocationID"] = new SelectList(_context.Location.Where(a=>a.Active == "Y").OrderBy(a => a.Name), "ID", "Name");
    ViewData["EventTypeID"] = new SelectList(_context.EventType.Where(a=>a.Active == "Y").OrderBy(a => a.Name), "ID","Name");
                
    return Page();
}

public async Task<IActionResult> OnPostAsync()
{
        
    if (!ModelState.IsValid)
    {
         ViewData["EntityID"] = new SelectList(_context.Entity.Where(a => a.Active == "Y").OrderBy(a => a.Name), "ID", "Name");
         ViewData["ShiftRangeID"] = new SelectList(_context.ShiftRange.Where(a => a.Active == "Y").OrderBy(a => a.Name), "ID", "Name");
         ViewData["LocationID"] = new SelectList(_context.Location.Where(a => a.Active == "Y").OrderBy(a => a.Name), "ID", "Name");//Not workiong                
         ViewData["EventTypeID"] = new SelectList(_context.EventType.Where(a => a.Active == "Y").OrderBy(a => a.Name), "ID", "Name");  
        //return Page(SecurityLog); // Return also the entity //Errors out "No overload for message 'Page ' takes 1 argument
        return Page();
    }
        

    _context.SecurityLog.Add(SecurityLog);    

    await _context.SaveChangesAsync();

    Message = "Entry added successfully!";

    //return RedirectToPage("Index");
    return Page();

}

验证失败时必须return列表和实体。

public IActionResult OnGetAsync()
{       
    ViewData["EntityID"] = new SelectList(_context.Entity.Where(a => a.Active == "Y").OrderBy(a => a.Name), "ID", "Name");                     
    ViewData["ShiftRangeID"] = new SelectList(_context.ShiftRange.Where(a=>a.Active == "Y").OrderBy(a => a.Name), "ID", "Name");
    ViewData["LocationID"] = new SelectList(_context.Location.Where(a=>a.Active == "Y").OrderBy(a => a.Name), "ID", "Name");
    ViewData["EventTypeID"] = new SelectList(_context.EventType.Where(a=>a.Active == "Y").OrderBy(a => a.Name), "ID","Name");
                
    return Page();
}

public async Task<IActionResult> OnPostAsync()
{
        
    if (!ModelState.IsValid)
    {
        // Where and When is invoked ? Is necessary for locations ?
        // FilteredLocation = new SelectList(_context.Location.Where(c => c.EntityID == entity).Where(c =>c.Active == "Y").OrderBy(c =>c.Name), "ID", "Name");
    
        // return new JsonResult(FilteredLocation);
        // Return the ViewData
        ViewData["EntityID"] = new SelectList(_context.Entity.Where(a => a.Active == "Y").OrderBy(a => a.Name), "ID", "Name");
        ViewData["ShiftRangeID"] = new SelectList(_context.ShiftRange.Where(a=>a.Active == "Y").OrderBy(a => a.Name), "ID", "Name");
        ViewData["LocationID"] = new SelectList(_context.Location.Where(a=>a.Active == "Y").OrderBy(a => a.Name), "ID", "Name");
        ViewData["EventTypeID"] = new SelectList(_context.EventType.Where(a=>a.Active == "Y").OrderBy(a => a.Name), "ID","Name");
        // Return also the entity
        // Somewhere you have to set SecurityLog
        return Page(); 
    }
        
    // From where came the SecurityLog ?
    _context.SecurityLog.Add(SecurityLog);    

    await _context.SaveChangesAsync();

    Message = "Entry added successfully!";

    // If you return always the same page, you must return also here the ViewData or move from it the top
    //return RedirectToPage("Index");
    return Page();

}