Search code examples
javascriptc#jqueryasp.net-core-mvcpartial-views

ASP.NET Core MVC update partial view after submitig a form


This is in ASP.NET Core MVC 2.1.

What I have is a main Index page on witch I load all my partial views.

<button type="button" id="CreateButton" class="btn btn-success" style="margin-top: 20px;">Nova osoba</button>
<button type="button" id="LoadDataButton" class="btn btn-info" style="margin-top: 20px;">Ucitati podatke</button>
<div id="CreateEditView">
</div>
<div id="TablePeopleView">
</div>

The way I load data into "TablePeopleView" is like this.

function AjaxCall(url) {
    $("#TablePeople").replaceWith(
        $.ajax({
            url: url,
            method: "POST",
            success: function (html) {
            $("#TablePeopleView").html(html);
            }
        }));
}

$(document).ready(function () {
   AjaxCall("@Url.Action("IndexAjax")");
});

This calls the IndexAjax method from the controller and creates this partial view inside "TablePeopleView"

@model List<Person>
<table style="margin-top: 20px;" class="table table-condensed" id="TablePeople">
<thead>
    <tr>
        <th>ID</th>
        <th>Ime</th>
        <th>Prezime</th>
        <th>Grad</th>
        <th>Postanski broj</th>
        <th>Broj mobitela</th>
        <th> </th>
        <th> </th>
    </tr>
</thead>
<tbody>
    @foreach (var item in Model)
    {
        <tr>
            <td>@item.ID</td>
            <td>@item.FirstName</td>
            <td>@item.LastName</td>
            <td>@item.CityName</td>
            <td>@item.PostalCode</td>
            <td>@item.MobileNumber</td>
            <td>
                <button type="button" class="btn btn-toolbar EditButton" data-url="@Url.Action("Edit","Zadatak")/@item.ID">
                    Uredi osobu
                </button>
            </td>
            <td>
                <button type="submit" class="btn btn-danger DeleteButton" data-url="@Url.Action("Delete","Zadatak")/@item.ID">
                    Obriši osobu
                </button>
            </td>
        </tr>
    }
</tbody>
</table>

And it works fine, gets the data and shows it on table.

When I want to create a new person I click on the "CreateButton" and get a new partial view inside "CreateEditView". The partial view looks like this.

@model Person
<div class="modal fade" id="CreateOrEditModal" role="dialog">
<div class="modal-dialog">
    <!-- Modal content-->
    <div class="modal-content">
        <div class="modal-header">

            @if (Model == null)
            {
                <h4 class="modal-title">Nova osoba</h4>
            }
            else
            {
                <h4 class="modal-title">Uredi osobu</h4>
            }
        </div>
        <div class="modal-body">
            <form asp-controller="Zadatak" id="CreateOrEditModalForm">
                <div class="form-group">
                    <label class="control-label">Ime osobe</label>
                    <input asp-for="FirstName" class="form-control" id="FirstName" />
                    <span asp-validation-for="FirstName" class="text-danger"></span>
                </div>

                <div class="form-group">
                    <label class="control-label">Prezime osobe</label>
                    <input asp-for="LastName" class="form-control" id="LastName" />
                    <span asp-validation-for="LastName" class="text-danger"></span>
                </div>

                <div class="form-group">
                    <label class="control-label">Naziv grada</label>
                    <input asp-for="CityName" class="form-control" id="CityName" />
                    <span asp-validation-for="CityName" class="text-danger"></span>
                </div>

                <div class="form-group">
                    <label class="control-label">Poštanski broj</label>
                    <input asp-for="PostalCode" class="form-control" id="PostalCode" onkeypress="return isNumberKey(event)" />
                    <span asp-validation-for="PostalCode" class="text-danger"></span>
                </div>

                <div class="form-group">
                    <label class="control-label">Mobilni broj</label>
                    <input asp-for="MobileNumber" class="form-control" id="MobileNumber" onkeypress="return isNumberKey(event)" />
                    <span asp-validation-for="MobileNumber" class="text-danger"></span>
                </div>

                <div class="form-group">
                    <input type="submit" value="Pospremi osobu" class="btn btn-default" id="SavePerson" />
                </div>
            </form>

        </div>
        <div class="modal-footer">
            <button type="button" id="ClosePerson" class="btn btn-default" data-dismiss="modal">Zatvori</button>
        </div>
    </div>

</div>
</div>

The way I get the partial view to show up in "CreateEditView" is like this.

$('#CreateButton').click(function () {
    var url = "@Url.Action("Create","Zadatak")";
    $("#CreateEditView").load(url, function () {
        $("#CreateOrEditModal").modal("show");
    });
});

The way I save date from the form "CreateOrEditModalForm" is with this.

$("#CreateEditView").on("click", "#SavePerson", function (event) {

    $("#CreateOrEditModalForm").removeData('validator');
    $("#CreateOrEditModalForm").removeData('unobtrusiveValidation');

    $.validator.unobtrusive.parse("#CreateOrEditModalForm");

    $("#CreateOrEditModalForm").validate();
    if ($("#CreateOrEditModalForm").valid()) {
        $("#CreateOrEditModal").modal("hide");
    }
});

I had to do it like this because it is loaded through a partial view witch is not loaded on page load.

After the form is validated it calls the "Create" method from the controller witch looks like this.

[HttpPost]
public IActionResult Create(Person model)
{

if (ModelState.IsValid)
    {
        this._dbContext.People.Add(model);
        this._dbContext.SaveChanges();
        return NoContent();
    }
    return NoContent();
}

Now this is where my problem comes I think. If the "ModelState.IsValid" is valid the new person will be saved to the DB and it will return NoContent. I put no content so the page does not refresh but if I put return RedirectToAction(nameof(IndexAjax)); like I did in the begginig it just loads the partila view in a new page like this.

I do not want that to happen, I just want the table to be refreshed with the new person while staying on the page.


Solution

  • Ajax allows websites to load content onto the screen without refreshing the page.

    Here is a working demo you could check:

    Model:

    public class Person
    {
        public int ID { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string CityName { get; set; }
        public string PostalCode { get; set; }
        public string MobileNumber { get; set; }
    }
    

    View(Views/Zadatak/Index.cshtml):

    <button type="button" id="CreateButton" class="btn btn-success" style="margin-top: 20px;">Nova osoba</button>
    <button type="button" id="LoadDataButton" class="btn btn-info" style="margin-top: 20px;">Ucitati podatke</button>
    <div id="CreateEditView">
    </div>
    <div id="TablePeopleView">
    </div>
    @section Scripts
    {   //be sure add _ValidationScriptsPartial....
        @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
        <script>
        function AjaxCall(url) {
            //the same as yours..
        }   
        $(document).ready(function () {
           AjaxCall("@Url.Action("IndexAjax")");
        });
        $('#CreateButton').click(function () {
            //the same as yours..
        });
        $("#CreateEditView").on("click", "#SavePerson", function (event) {    
            $("#CreateOrEditModalForm").removeData('validator');
            $("#CreateOrEditModalForm").removeData('unobtrusiveValidation');
            $.validator.unobtrusive.parse("#CreateOrEditModalForm"); 
            $("#CreateOrEditModalForm").validate();
            if ($("#CreateOrEditModalForm").valid()) {
                $("#CreateOrEditModal").modal("hide");
    
               //add the following code....
    
                $("#TablePeople").replaceWith(
                    $.ajax({
                        url:"@Url.Action("Create", "Zadatak")",
                        method: "POST",
                        data: $("#CreateOrEditModalForm").serialize(),
                        success: function (html) {
                            $("#TablePeopleView").html(html);
                        }
                    }));
            }
        });
        </script>
    }
    

    Be sure modify your CreateEditView.cshtml:

    @model Person
    <div class="modal fade" id="CreateOrEditModal" role="dialog">
        //...
    
                        <div class="form-group">
                            @*change type="submit" to type="button"*@
                            <input type="button" value="Pospremi osobu" class="btn btn-default" id="SavePerson" />
                        </div>
                    </form>
    
                </div>
                <div class="modal-footer">
                    <button type="button" id="ClosePerson" class="btn btn-default" data-dismiss="modal">Zatvori</button>
                </div>
            </div>
    
        </div>
    </div>
    

    Controller:

    public class ZadatakController : Controller
    {
        private readonly YourContext _context;
    
        public ZadatakController(YourContext context)
        {
            _context = context;
        }
        [HttpGet]
        public async Task<IActionResult> Index()
        {
            return View();
        }
        [HttpPost]
        public async Task<IActionResult> IndexAjax()
        {
            //change here....
            return PartialView("_IndexTable", await _context.Person.ToListAsync());
        }
        public IActionResult Create()
        {
            return PartialView("CreateEditView");
        }
        [HttpPost]
        public async Task<IActionResult> Create(Person person)
        {
            if (ModelState.IsValid)
            {
                _context.Add(person);
                await _context.SaveChangesAsync();
    
                //change here....
                return PartialView("_IndexTable", await _context.Person.ToListAsync());
    
            }
            return View(person);
        }
    }
    

    Result:

    enter image description here