0

I tried to write a code and scripts using ASP.NET MVC 5. Was I use modal to do Create, Update, and Delete functionality which is working properly but when it comes with Creating, and Updating because I enable remote validations, it works at first but suddenly when you click again the submit button it will submit or post the data. In short, my validation is not working. Please, I need help.

Model:

[Key]
[Display(Name = "ID")]
[Column("LAND_TYPE_CAT_ID", Order = 0, TypeName = "bigint")]
public long CategoryId { get; set; }

[Display(Name = "Category Name")]
[StringLength(100)]
[Column("LAND_TYPE_CAT", Order = 1, TypeName = "nvarchar")]
public string CategoryName { get; set; }

[Display(Name = "Description")]
[StringLength(255)]
[Column("LAND_TYPE_CAT_DESC", Order = 2, TypeName = "nvarchar")]
public string CategoryDescription { get; set; }

[Display(Name = "Created Date")]
[Column("CREATE_DATE", Order = 3, TypeName = "datetime")]
public DateTime? CreateDate { get; set; }

[Display(Name = "Modified Date")]
[Column("MODIFIED_DATE", Order = 4, TypeName = "datetime")]
public DateTime? ModifiedDate { get; set; }

[Display(Name = "Last Modified By")]
[StringLength(255)]
[Column("LAST_MODIFIED_BY", Order = 5, TypeName = "nvarchar")]
public string LastModifiedBy { get; set; }

ViewModels: For Create:

[Display(Name = "Category Name")]
[Required(ErrorMessage = "This field is required.")]
[Remote("ValidateCreate", "Category", ErrorMessage = "This type already exists.")]
public string CategoryName { get; set; }

For Update:

[Display(Name = "Category Name")]
[Required(ErrorMessage = "This field is required.")]
[Remote("ValidateEdit", "Category", AdditionalFields = "CategoryId, CategoryName",
    ErrorMessage = "This type already exists.")]
public string CategoryName { get; set; }

Controller:

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Create(LandTypeCategoryCreateViewModels viewModel)
{
    if (ModelState.IsValid)
    {
        var vm = new LandTypeCategory
        {
            CategoryName = viewModel.CategoryName,
            CategoryDescription = viewModel.CategoryDescription,
            CreateDate = DateTime.Now,
            LastModifiedBy = "Tester"
        };

        _context.LandTypeCategories.Add(vm);
        await _context.SaveChangesAsync();

        TempData["Created"] = "New category type added.";
        var url = Url.Action("Index", "Category", new {id = viewModel.CategoryId});
        return Json(new {success = true, url});
    }

    return PartialView("_Create", viewModel);
}

public async Task<ActionResult> Edit(long? id)
{
    if (id == null)
        return new HttpStatusCodeResult(HttpStatusCode.BadRequest);

    var vm = await _context.LandTypeCategories.FindAsync(id);

    if (vm == null)
        return HttpNotFound();

    var viewModel = new LandTypeCategoryEditViewModels
    {
        CategoryId = vm.CategoryId,
        CategoryName = vm.CategoryName,
        CategoryDescription = vm.CategoryDescription
    };

    return PartialView("_Edit", viewModel);
}

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Edit(LandTypeCategoryEditViewModels viewModel)
{
    if (ModelState.IsValid)
    {
        var vm =
            await _context.LandTypeCategories.SingleAsync(x => x.CategoryId == viewModel.CategoryId);

        vm.CategoryName = viewModel.CategoryName;
        vm.CategoryDescription = viewModel.CategoryDescription;
        vm.ModifiedDate = DateTime.Now;
        vm.LastModifiedBy = "Modify Tester";

        _context.Entry(vm).State = EntityState.Modified;
        await _context.SaveChangesAsync();

        TempData["Updated"] = "Category type updated.";
        var url = Url.Action("Index", "Category", new {id = viewModel.CategoryId});
        return Json(new {success = true, url});
    }

    return PartialView("_Edit", viewModel);
}

Remote Validation:

public async Task<JsonResult> ValidateCreate(string CategoryName)
{
    return
        Json(
            await _context.LandTypeCategories.AllAsync(
                c => c.CategoryName.ToLower() != CategoryName.ToLower()), JsonRequestBehavior.AllowGet);
}

public async Task<JsonResult> ValidateEdit(int CategoryId, string CategoryName)
{
    var category = await _context.LandTypeCategories.FindAsync(CategoryId);
    var result = true;

    if (category.CategoryName.ToLower() != CategoryName.ToLower())
        result =
            await _context.LandTypeCategories.AllAsync(
                c => c.CategoryName.ToLower() != CategoryName.ToLower());

    return Json(result, JsonRequestBehavior.AllowGet);
}

Index.cshtml

@model IEnumerable<MvcPPT.Models.LandTypeCategory>

@{
    ViewBag.Title = "Category";
}

<div class="container">
    <br />
    <br />
    <br />
    @Html.ActionLink("Add New", "Create", "Category", new { ViewBag.CategoryId }, new { data_modal = "", @class = "btn btn-primary", style = "position: absolute;background-color: #3498db; border-color: #3498db;" })
    <table class="table table-hover table-bordered" id="same-datatable" style="font-size: smaller; width: 100%;">
        <thead>
            <tr>
                <th>@Html.DisplayNameFor(model => model.CategoryId)</th>
                <th>@Html.DisplayNameFor(model => model.CategoryName)</th>
                <th>@Html.DisplayNameFor(model => model.CategoryDescription)</th>
                <th>@Html.DisplayNameFor(model => model.CreateDate)</th>
                <th>@Html.DisplayNameFor(model => model.ModifiedDate)</th>
                <th>@Html.DisplayNameFor(model => model.LastModifiedBy)</th>
                <th>Action</th>
            </tr>
        </thead>
        <tbody>
            @foreach (var item in Model)
            {
                <tr>
                    <td>@Html.DisplayFor(modelItem => item.CategoryId)</td>
                    <td>@Html.DisplayFor(modelItem => item.CategoryName)</td>
                    <td>@Html.DisplayFor(modelItem => item.CategoryDescription)</td>
                    <td>@Html.DisplayFor(modelItem => item.CreateDate)</td>
                    <td>@Html.DisplayFor(modelItem => item.ModifiedDate)</td>
                    <td>@Html.DisplayFor(modelItem => item.LastModifiedBy)</td>
                    <td>
                        @Html.ActionLink("Edit", "Edit", "Category", new { id = item.CategoryId }, new { data_modal = "", @class = "btn btn-warning btn-xs" })
                        &nbsp;
                        @Html.ActionLink("Delete", "Delete", "Category", new { id = item.CategoryId }, new { data_modal = "", @class = "btn btn-danger btn-xs" })
                    </td>
                </tr>
            }
        </tbody>
    </table>
</div>

<div id="myModal" class="modal fade" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
    <div class="modal-dialog">
        <div class="modal-content">
            <div id="myModalContent"></div>
        </div>
    </div>
</div>

_Create.cshtml

@model MvcPPT.ViewModels.LandTypeCategoryCreateViewModels

<div class="modal-header" style="background-color: #3498db; color: #fff;">
    <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
    <h4 class="modal-title" id="myModalLabel">Add New Category Type</h4>
</div>

@using (Html.BeginForm())
{
    <div class="modal-body">
        @Html.AntiForgeryToken()

        <div class="form-horizontal">
            @Html.ValidationSummary(true, "", new {@class = "text-danger"})
            <div class="form-group">
                @Html.LabelFor(model => model.CategoryName, new {@class = "control-label col-md-4"})
                <div class="col-md-8">
                    @Html.EditorFor(model => model.CategoryName, new {htmlAttributes = new {@class = "form-control"}})
                    @Html.ValidationMessageFor(model => model.CategoryName, "", new {@class = "text-danger"})
                </div>
            </div>
            <div class="form-group">
                @Html.LabelFor(model => model.CategoryDescription, new {@class = "control-label col-md-4"})
                <div class="col-md-8">
                    @Html.EditorFor(model => model.CategoryDescription, new {htmlAttributes = new {@class = "form-control"}})
                    @Html.ValidationMessageFor(model => model.CategoryDescription, "", new {@class = "text-danger"})
                </div>
            </div>
            <div class="modal-footer" style="padding-right: 0px;">
                <input class="btn btn-success" type="submit" value="Save"/>
                <button class="btn btn-default" type="button" data-dismiss="modal">Cancel</button>
            </div>
        </div>
    </div>
}

@Scripts.Render("~/bundles/jqueryval")

_Edit.cshtml

@model MvcPPT.ViewModels.LandTypeCategoryCreateViewModels

<div class="modal-header" style="background-color: #3498db; color: #fff;">
    <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
    <h4 class="modal-title" id="myModalLabel">Add New Category Type</h4>
</div>

@using (Html.BeginForm())
{
    <div class="modal-body">
        @Html.AntiForgeryToken()

        <div class="form-horizontal">
            @Html.ValidationSummary(true, "", new {@class = "text-danger"})
            <div class="form-group">
                @Html.LabelFor(model => model.CategoryName, new {@class = "control-label col-md-4"})
                <div class="col-md-8">
                    @Html.EditorFor(model => model.CategoryName, new {htmlAttributes = new {@class = "form-control"}})
                    @Html.ValidationMessageFor(model => model.CategoryName, "", new {@class = "text-danger"})
                </div>
            </div>
            <div class="form-group">
                @Html.LabelFor(model => model.CategoryDescription, new {@class = "control-label col-md-4"})
                <div class="col-md-8">
                    @Html.EditorFor(model => model.CategoryDescription, new {htmlAttributes = new {@class = "form-control"}})
                    @Html.ValidationMessageFor(model => model.CategoryDescription, "", new {@class = "text-danger"})
                </div>
            </div>
            <div class="modal-footer" style="padding-right: 0px;">
                <input class="btn btn-success" type="submit" value="Save"/>
                <button class="btn btn-default" type="button" data-dismiss="modal">Cancel</button>
            </div>
        </div>
    </div>
}

@Scripts.Render("~/bundles/jqueryval")

jQuery How Modal Call:

// Add new
    $.ajaxSetup({ cache: false });
    $("a[data-modal]").on("click",
        function (e) {
            $("#myModalContent").load(this.href,
                function () {
                    $("#myModal").modal({
                        keyboard: true
                    },
                        "show");
                    bindForm(this);
                });
            return false;
        });

function bindForm(dialog) {
    $("form", dialog).submit(function () {
        $.ajax({
            url: this.action,
            type: this.method,
            data: $(this).serialize(),
            success: function (result) {
                if (result.success) {
                    $("#myModal").modal("hide");
                    window.location.reload();
                } else {
                    $("#myModalContent").html(result);
                    bindForm(dialog);
                }
            }
        });
        return false;
    });
}
Patrick
  • 21
  • 2
  • 8

2 Answers2

0

since both create and edit forms are partial views which i am guessing will render on same Main view i will advice you to remove the

  @Scripts.Render("~/bundles/jqueryval")

from both partial pages and add the line in the top of main page since when you click the create button it will load the script bundle and again when you click the edit it will load them for the 2nd time

next is properly write the @gtml.begin form tags like

  @using (Html.BeginForm(ActionName , ControllerName, FormMethod.Post))

i am not sure how is your form post is workng now

RAHUL S R
  • 1,569
  • 1
  • 11
  • 20
0

Option 1:

You can disable the button once it is submitted then.

$('form').submit(function() {
    $(this).find(':submit').attr('disabled', 'disabled');
});

Option 2:

By creating a action filter. (So here you can validate duplication of anti-forgery token.)

How do I prevent multiple form submission in .NET MVC without using Javascript?

Power Star
  • 1,724
  • 2
  • 13
  • 25