I have a model that is shared between two pages (Security Log, Lost and Found). I am looking to require the property, 'Narrative', only if the property, 'AppType' = "Security Log".
I have the server side validation working fine, but when I go to save the form, the drop-down values on my form lose their values because I am using ViewBag. This is what I currently have.
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;
}
}
Does anyone know how I can implement client side validation (javascript/jquery/etc..) on my Security Log create page? I am finding that the rest of my project's required fields validate client side because the drop-down values are retained. When I have all required fields except for Narrative filled-out and click save, then I lose the dd values so I know this is being handled server side.
Sample of create page before clicking save
Sample of create page after clicking save
Create page logic
<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();
}
You must return the List and the entity when validation fail.
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();
}