1

I am building a website with MVC and I have a view with a form. I want validation to appear when users leave a field blank, however I can not get this to work. I have tried adding the Data annotation tags in the model, the asp-validation-for span, and checking the ModelState in the post action.

Here is my Model:

using System;
using IssueTracker.Areas.Identity.Data;
using System.ComponentModel.DataAnnotations;
using System.Xml.Linq;

namespace IssueTracker.Models
{
    public class EditProjectViewModel
    {
        public EditProjectViewModel()
        {
            this.Users = new List<ApplicationUser>();
            this.OtherUsers = new List<ApplicationUser>();
        }

        public int Id { get; set; }

        [Required]
        public string? Name { get; set; }

        [Required]
        public string? Description { get; set; }

        [Required]
        public string? Status { get; set; }

        [Required]
        public string? ClientCompany { get; set; }

        [Required]
        public string? ProjectLeader { get; set; }

        [Required]
        public virtual List<ApplicationUser> Users { get; set; }

        [Required]
        public virtual List<ApplicationUser> OtherUsers { get; set; }

    }
}

and here is my View:

@using IssueTracker.Areas.Identity.Data
@using Microsoft.AspNetCore.Identity
@inject UserManager<ApplicationUser> userManager
@model EditProjectViewModel
@{
    ViewData["Title"] = "Edit Project: " + Model.Name;
}

@section Scripts2
{
    <link rel="stylesheet" href="../../dist/plugins/select2/css/select2.min.css">
}

<!-- Main content -->
<section class="content">
    <div class="row">
        <div class="col-md-12">
            <div class="card card-info">
                <div class="card-header">
                    <h3 class="card-title">Edit Your Project</h3>
                </div>
                <div class="card-body">
                    <form method="post">
                        <div class="form-group">
                            <label for="inputName">Project Name:</label>
                            <textarea id="inputName" name="Name" class="form-control" rows="1">@Model.Name</textarea>
                            <span asp-validation-for="Name" class="text-danger"></span>
                        </div>
                        <div class="form-group">
                            <label for="inputDescription">Project Description:</label>
                            <textarea id="inputDescription" name="Description" class="form-control" rows="3">@Model.Description</textarea>
                            <span asp-validation-for="Description" class="text-danger"></span>
                        </div>
                        <div class="form-group">
                            <label for="inputStatus">Status:</label>
                            <select asp-for="Status" id="inputStatus" name="Status" class="form-control custom-select">
                                <option selected value="@Model.Status">@Model.Status</option>
                                @if (Model.Status != "In Development")
                                {
                                    <option value="In Development">In Development</option>
                                }
                                @if (Model.Status != "On Hold")
                                {
                                    <option value="On Hold">On Hold</option>
                                }
                                @if (Model.Status != "Revising")
                                {
                                    <option value="Revising">Revising</option>
                                }
                                @if (Model.Status != "Completed")
                                {
                                    <option value="Completed">Completed</option>
                                }
                                @if (Model.Status != "Withdrawn")
                                {
                                    <option value="Withdrawn">Withdrawn</option>
                                }
                            </select>
                            <span asp-validation-for="Status" class="text-danger"></span>
                        </div>
                        <div class="form-group">
                            <label for="inputCompany">Client Company:</label>
                            <textarea asp-for="ClientCompany" id="inputCompany" name="ClientCompany" class="form-control" rows="1">@Model.ClientCompany</textarea>
                            <span asp-validation-for="ClientCompany" class="text-danger"></span>
                        </div>
                        <div class="form-group">
                            <label for="inputLeader">Project Leader:</label>
                            <select asp-for="ProjectLeader" id="inputLeader" name="ProjectLeader" class="form-control custom-select">
                                <option selected value="@Model.ProjectLeader">@(userManager.FindByIdAsync(Model.ProjectLeader).Result.FirstName + " " + userManager.FindByIdAsync(Model.ProjectLeader).Result.LastName)</option>
                                @foreach (ApplicationUser user in userManager.Users)
                                {
                                    if (user != userManager.FindByIdAsync(Model.ProjectLeader).Result)
                                    {
                                        <option value="@user.Id">@(user.FirstName + " " + user.LastName)</option>
                                    }
                                }
                            </select>
                            <span asp-validation-for="ProjectLeader" class="text-danger"></span>
                        </div>
                        <div class="form-group">
                            <label>Select 1 or More Contributors:</label>
                            <div class="select2-blue">
                                <select asp-for="Users" class="select2" name="Contributors" multiple="multiple" data-dropdown-css-class="select2-blue" data-placeholder="Select a Contributors" style="width: 100%;">
                                    @foreach (ApplicationUser user in Model.Users)
                                    {
                                        <option value="@user.Id" selected>@(user.FirstName + " " + user.LastName)</option>
                                    }
                                    @foreach (ApplicationUser user in Model.OtherUsers)
                                    {
                                        <option value="@user.Id">@(user.FirstName + " " + user.LastName)</option>
                                    }
                                </select>
                            </div>
                            <span asp-validation-for="Users" class="text-danger"></span>
                        </div>
                        <div class="row">
                            <div class="col-12">
                                <a asp-controller="Home" asp-action="Projects" class="btn btn-secondary">Cancel</a>
                                <input type="submit" asp-route-id="@Model.Id" value="Update Project" class="btn btn-success float-right">
                            </div>
                        </div>
                    </form>
                </div>
                <!-- /.card-body -->
            </div>
            <!-- /.card -->
        </div>
    </div>
</section>
<!-- /.content -->
<!-- /.content-wrapper -->

@section Scripts{
    <script src="../../dist/plugins/select2/js/select2.full.min.js"></script>
    <script>$(function () {
            $('.select2').select2()

        })</script>
}

Lastly, here is my controller method:

[HttpPost]
    public async Task<IActionResult> EditProject(int Id, string Name, string Description, string Status, string ClientCompany,
                                                string ProjectLeader, List<string> Contributors)
    {
        if (ModelState.IsValid)
        {
            var project = await db.Projects.FindAsync(Id);

            if (project == null)
            {
                return View("Error");
            }
            else
            {
                project.Name = Name;
                project.Description = Description;
                project.Status = Status;
                project.ClientCompany = ClientCompany;
                project.ProjectLeader = ProjectLeader;
            }

            db.Entry(project).Collection("Users").Load();
            foreach (ApplicationUser user in project.Users)
            {
                db.Entry(user).Collection("Projects").Load();
                user.Projects.Remove(project);
                db.Users.Update(user);
            }
            project.Users.Clear();

            foreach (string Contributor in Contributors)
            {
                project.Users.Add(await userManager.FindByIdAsync(Contributor));
                userManager.FindByIdAsync(Contributor).Result.Projects.Add(project);
            }

            project.Users.Add(userManager.FindByIdAsync(ProjectLeader).Result);
            userManager.FindByIdAsync(ProjectLeader).Result.Projects.Add(project);

            db.Projects.Update(project);
            await db.SaveChangesAsync();

            return RedirectToAction("Projects");

        }

        return RedirectToAction("EditProject", Id);
    }

Whenever I submit a form and leave fields blank, the page just refreshes and doesn't save any changes. Instead, I want the error validation messages to pop up. How can I achieve this? Thank you!

Ryan Tobin
  • 53
  • 1
  • 6

1 Answers1

0

For the html validation in View to work with asp.net data validation attributes defined in EditProjectViewModel, you will need javascript/jquery unobtrusive behavior. That will help you generate much of the validation code as well as do the validation for you based on the data attributes defined in the model.

You can take this answer as reference and for help: What is jQuery Unobtrusive Validation?

Ali Khan
  • 138
  • 9