Search code examples
jqueryajaxasp.net-coreasp.net-core-mvc

Inline editing in ASP.NET Core MVC using AJAX, error 400 (Bad Request)


I am trying to make inline edit using AJAX in ASP.NET Core MVC. Every time I get an error 400 (Bad Request)

I need to click on the row of the table to edit and save in SQL database with the new values.

Is what I am doing correct or am I wrong about something? Please also clarify if there is a better way than that

My Index.cshtml:

@model IEnumerable<officeprotocol.Areas.UpdatedThankReq.Models.MainTexts>

<table class="table" id="tstTable">
    <thead>
        <tr>
            <th>
                @Html.DisplayNameFor(model => model.Id)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.BeginText)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.EndText)
            </th>
            <th></th>
        </tr>
    </thead>
    <tbody>
        @foreach (var item in Model)
        {
            <tr>
                <td class="maintxtId">
                    <span id="idVal">@item.Id</span>
                </td>
                <td class="maintxtBegin">
                    <span>@item.BeginText</span>
                    <input id="bgnTxtIn" type="text" value="@item.BeginText" style="display:none"/>
                </td>
                <td class="maintxtEnd">
                    <span>@item.EndText</span>
                    <input id="endTxtIn" type="text" value="@item.EndText" style="display:none" />
                </td>
                <td>
                    <a class="Edit" href="javascript:;">Edit</a>
                    <a class="Update" href="javascript:;" style="display:none">Update</a>
                    <a class="Cancel" href="javascript:;" style="display:none">Cancel</a>
                    <a class="Delete" href="javascript:;">Delete</a>
                </td>
            </tr>
        }
    </tbody>
</table>

@section scripts 
{
    <script src="~/lib/jquery/dist/jquery.min.js"></script>
    <script src="~/lib/jquery/dist/jquery.js"></script>

    <script type="text/javascript">
    $(document).ready(function () {
        $("body").on("click", '#tstTable .Edit', function () {
            var row = $(this).closest("tr");
            $("td", row).each(function () {
                if ($(this).find("input").length > 0) {
                    $(this).find("input").show();
                    $(this).find("span").hide();
                }
            });

            row.find(".Update").show();
            row.find(".Cancel").show();
            row.find(".Delete").hide();
            $(this).hide();
        });

        $("body").on("click", '#tstTable .Update', function () {
            var row = $(this).closest("tr");
            $("td", row).each(function () {
                if ($(this).find("input").length > 0) {
                    var span = $(this).find("span");
                    var input = $(this).find("input");
                    span.html(input.val());
                    span.show();
                    input.hide();
                }
            });

            row.find(".Edit").show();
            row.find(".Delete").show();
            row.find(".Cancel").hide();

            $(this).hide();

            var MaintxtViewModel = {
                                        Id: parseInt($("#idVal").html()),
                                        BeginText: $("#bgnTxtIn").val(),
                                        EndText: $("#endTxtIn").val()

                                        // Id: parseInt(row.find(".maintxtId").find("span").html()),
                                        // BeginText: row.find(".maintxtBegin").find("span").html(),
                                        // EndText: row.find(".maintxtEnd").find("span").html()
                                    };

            $.ajax ({
                  type: 'POST',
                  url: "/ReqArea/MainTexts/Edit",
                  data: { mainTexts: MaintxtViewModel },

                  success: function (result) {
                      alert("Saved");
                  },
                  failure: function (result) {
                      alert("Failed")
                  },
                  error: function (result) {
                      alert("SaveError");
                  }
              });
          });
      });
    </script>
}

My Controller in area

    public async Task<IActionResult> Edit(int? id)
    {
        if (id == null || _context.MainTexts == null)
        {
            return NotFound();
        }

        var mainTexts = await _context.MainTexts.FindAsync(id);

        if (mainTexts == null)
        {
            return NotFound();
        }

        return View(mainTexts);
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> Edit(int id, [Bind("Id,BeginText,EndText")] MainTexts mainTexts)
    {
        if (id != mainTexts.Id)
        {
            return NotFound();
        }

        if (ModelState.IsValid)
        {
            try
            {
                _context.Update(mainTexts);
                await _context.SaveChangesAsync();
            }
            catch (DbUpdateConcurrencyException)
            {
                if (!MainTextsExists(mainTexts.Id))
                {
                    return NotFound();
                }
                else
                {
                    throw;
                }
            }
            return RedirectToAction(nameof(Index));
        }
        return View(mainTexts);
}

enter image description here

I've tried many times to solve this.

Now all what I need is to run the action


Solution

  • Remove the [ValidateAntiForgeryToken] attribute will solve your current issue.

    Here are also some additional problems below:

    1.Remember to pass the id in the route:

    url: "/ReqArea/MainTexts/Edit/" + parseInt($("#idVal").html()),
    

    2.The code which you used to get input value wil always get the first tr, you need modify your js code:

    var MaintxtViewModel = {
            Id: parseInt($(this).closest('tr').find('td span#idVal').html()),
            BeginText: $(this).closest('tr').find('td input#bgnTxtIn').val(),
            EndText: $(this).closest('tr').find('td input#endTxtIn').val()
                            };
    

    3.The value attribute is always the original value, add the js code:

    var defaultBgnTxtInValue = $("#bgnTxtIn").val();
    var defaultEndTxtInValue = $("#endTxtIn").val();
        $("table input[type='text']").on("change", function () {
            // Get the parent <td> and <tr> elements of the changed input
            var tdElement = $(this).closest("td");
            var trElement = $(this).closest("tr");
    
            // Get the ID of the changed input element
            var changedInputId = $(this).attr("id");
            var newValue = $(this).val();
            if (changedInputId == "bgnTxtIn") {
                if (newValue !== defaultBgnTxtInValue) {
                    // Update the default value with the new value
                    $(this).attr('value', newValue);
                }
            }
            else {
                if (newValue !== defaultEndTxtInValue) {
                    // Update the default value with the new value
                    $(this).attr('value', newValue);
                }
            }
        });
    $("body").on("click", '#tstTable .Edit', function () {
        var row = $(this).closest("tr");
        $("td", row).each(function () {
            if ($(this).find("input").length > 0) {
                $(this).find("input").show();
                $(this).find("span").hide();
            }
        });
    
        row.find(".Update").show();
        row.find(".Cancel").show();
        row.find(".Delete").hide();
        $(this).hide();
            
    });
    

    The whole js code

    @section scripts 
    {
        <script type="text/javascript">
        $(document).ready(function () {
            var defaultBgnTxtInValue = $("#bgnTxtIn").val();
            var defaultEndTxtInValue = $("#endTxtIn").val();
                $("table input[type='text']").on("change", function () {
                    // Get the parent <td> and <tr> elements of the changed input
                    var tdElement = $(this).closest("td");
                    var trElement = $(this).closest("tr");
    
                    // Get the ID of the changed input element
                    var changedInputId = $(this).attr("id");
                    var newValue = $(this).val();
                    if (changedInputId == "bgnTxtIn") {
                        if (newValue !== defaultBgnTxtInValue) {
                            // Update the default value with the new value
                            $(this).attr('value', newValue);
                        }
                    }
                    else {
                        if (newValue !== defaultEndTxtInValue) {
                            // Update the default value with the new value
                            $(this).attr('value', newValue);
                        }
                    }
                });
            $("body").on("click", '#tstTable .Edit', function () {
                var row = $(this).closest("tr");
                $("td", row).each(function () {
                    if ($(this).find("input").length > 0) {
                        $(this).find("input").show();
                        $(this).find("span").hide();
                    }
                });
    
                row.find(".Update").show();
                row.find(".Cancel").show();
                row.find(".Delete").hide();
                $(this).hide();
                    
            });
               
            $("body").on("click", '#tstTable .Update', function () {
                var row = $(this).closest("tr");
                $("td", row).each(function () {
                    if ($(this).find("input").length > 0) {
                        var span = $(this).find("span");
                        var input = $(this).find("input");
                        span.html(input.val());
                        span.show();
                        input.hide();
                    }
                });
    
                row.find(".Edit").show();
                row.find(".Delete").show();
                row.find(".Cancel").hide();
    
                $(this).hide();
    
    var MaintxtViewModel = {
            Id: parseInt($(this).closest('tr').find('td span#idVal').html()),
            BeginText: $(this).closest('tr').find('td input#bgnTxtIn').val(),
            EndText: $(this).closest('tr').find('td input#endTxtIn').val()
    
                                // Id: parseInt(row.find(".maintxtId").find("span").html()),
                                // BeginText: row.find(".maintxtBegin").find("span").html(),
                                // EndText: row.find(".maintxtEnd").find("span").html()
                            };
    
                $.ajax ({
                      type: 'POST',
                        url: "/ReqArea/MainTexts/Edit/" + parseInt($(this).closest('tr').find('td span#idVal').html()),
                      data: { mainTexts: MaintxtViewModel },
    
                      success: function (result) {
                          alert("Saved");
                      },
                      failure: function (result) {
                          alert("Failed")
                      },
                      error: function (result) {
                          alert("SaveError");
                      }
                  });
              });
          });
        </script>
    }