+2

Hướng dẫn load một phần trong trang (partial view) mà không reload lại trang dùng jQuery

Trong app MVC đôi khi chúng ta muốn thay đổi một phần trong trang (page) mà không muốn phải reload (refresh) lại trang đó thì chúng ta có thể dùng kĩ thuật Ajax để load dữ liệu sau đó dùng javascript để render. Ví dụ trong trang nhập thông tin địa chỉ cá nhân, có một select element để chọn tỉnh và một select element để chọn huyện của tỉnh đó. Yêu cầu là khi người dùng chọn (thay đổi) options ở select tỉnh thì options trong select huyện phải là các huyện ở trong tỉnh đã được chọn. Đây là một usecase kĩ thuật không phức tạp nhưng lại được sử dụng rất nhiều. Hôm nay mình sẽ hướng dẫn các bạn thực hiện yêu cầu này cho app ASP.NET Core MVC kết hợp jQuery. Ý tưởng là mình sẽ bắt sự kiện thay đổi (changed) của select chọn tỉnh, khi có sự thay đổi thì mình sẽ lấy giá trị mới đó gửi tới server để get danh sách options chọn huyện.

Yêu cầu

  • Có kiến thức cơ bản về lập trình web, mô hình MVC, ASP.NET Core MVC
  • Có kiến thức cơ bản HTML, Javascript, jQuery

(Yêu cầu vậy thôi nhưng mình nghĩ nếu bắt đầu thì các bạn sẽ thấy không phức tạp đâu)

Bắt đầu thôi nào! Đầu tiên thì mình sẽ tạo một web app MVC. Ở đây mình sử dụng .NET Core 8.0 nhưng các bạn có thể sử dụng bất kì version nào, thậm chí ở các ngôn ngữ khác hay framework khác cũng đều cùng một cơ chế. Mình chuẩn bị sẵn model, view, và controller như sau: Controller:

public class HomeController : Controller
{
    public IActionResult Index()
    {
        ViewBag._ProvinceSelectListItems = new List<SelectListItem>
        {
            new ("Ha Noi", 1.ToString())
            , new ("Da Nang", 2.ToString())
            , new ("Ho Chi Minh", 3.ToString())
        };
        return View();
    }
}

Controller không có gì đặc biệt cả, chỉ gồm một action để render view. Trong action này mình chuẩn bịt một list các SelectListItem (text là tên tỉnh và value là id của tỉnh) gồm danh sách các tỉnh để chọn, sau đó set vào ViewBag để dùng ở view. Trong dự án thực tế thì mấy cái SelectListItem này thường được get từ database nhưng để demo ngắn gọn thì mình code cứng như thế này. Model:

public class IndexViewModel
{
    public int ProvinceId { get; set; }
    public int PrefectureId { get; set; }
}

Model đơn giản gồm 2 property: ProvinceId là id của tỉnh và PrefectureId là id của huyện. View (Index.cshtml):

@model IndexViewModel
@{
    var provinceSelectListItems = ViewBag._ProvinceSelectListItems as List<SelectListItem>;
}
<div>
    <label>Province</label>
    <select asp-for="ProvinceId" asp-items="provinceSelectListItems"></select>
</div>
<div>
    <label>Prefecture</label>
    <select asp-for="PrefectureId"></select>
</div>

View thì như đã nói ở trên mình, mình tạo 2 select, 1 để chọn tỉnh và 1 để chọn huyện. Select chọn tỉnh có các options là những item mà mình đã khởi tạo strong controller action. Và đây là hình ảnh đầu: image.png   Sau đó mình sẽ tạo một action PrefectureOptionsPartial trong HomeController, trả về một partial view gồm các options chọn huyện dựa theo parameter PrefectureId (id của tỉnh). Ví dụ id là 1 (Hà Nội) thì mình sẽ trả về options Hoàn Kiếm, Cầu Giấy.

 [HttpGet("PrefectureOptionsPartial")]
    public IActionResult PrefectureOptionsPartial(int PrefectureId)
    {
        ViewBag._PrefectureSelectListItems = PrefectureId switch
        {
            1 => new List<SelectListItem>
                {
                    new ("Hoan Kiem", 1.ToString())
                    , new ("Cau Giay", 2.ToString())
                },
            2 => new List<SelectListItem>
                {
                    new ("Hai Chau", 1.ToString())
                    , new ("Lien Chieu", 2.ToString())
                },
            3 => new List<SelectListItem>
                {
                    new ("Quan 1", 1.ToString())
                    , new ("Quan 7", 2.ToString())
                },
            _ => new List<SelectListItem>()
        };
        return PartialView("/Views/Home/_PrefectureOptions.cshtml");
    }

Và thêm một file partial view _PrefectureOptions.cshtml như sau để render ra các options:

@{
    var prefectureSelectListItems = ViewBag._PrefectureSelectListItems as List<SelectListItem>; 
}
@foreach(var item in prefectureSelectListItems) 
{
    <option value="@item.Value">@item.Text</option>
}

Và trong file Index.cshtml mình thêm đoạn script đây:

<script>
    $(function() {
        // Add listener cho sự kiện changed của select chọn tỉnh
        $('select[name=@Html.NameFor(m => m.ProvinceId)]').change(function() {
            //Lấy giá trị tỉnh của tỉnh đã chọn
            const ProvinceId = $(this).find(':selected').val();
            //Tạo url để request options list cho tỉnh đã chọn. 
            const url = new URL('@Url.Action(nameof(HomeController.PrefectureOptionsPartial))', location.origin);
            url.searchParams.set('PrefectureId', ProvinceId);
           $('select[name=@Html.NameFor(m => m.PrefectureId)]').load(url.href);
        });
    })
</script>

Ở đây mình sử dụng hàm load của jQuery fetch view gồm các options chọn huyện từ server về sau đó nạp vào select chọn huyện. Và đây là kết quả. Untitled.gif Nếu bạn có thắc mắc, ý kiến đóng góp gì xin vui lòng để lại bình luận nhé.


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí