Cấp bậc tác giả:

DOTNET

Hướng dẫn Xây dựng Hệ thống Quản lý Tin tức kết hợp giữa ASP.NET MVC Core và Ajax

Được viết bởi webmaster ngày 08/12/2023 lúc 11:48 AM
Bài viết dưới đây sẽ hướng dẫn học viên cách để xây dựng một chức năng quản lý hoàn hảo bao gồm CRUD(ví dụ cụ thể về quản lý tin tức) kết hợp giữa MVC Core và Ajax
  • 0
  • 2296

Hướng dẫn Xây dựng Hệ thống Quản lý Tin tức kết hợp giữa ASP.NET MVC Core và Ajax

1. Tạo Cơ sở dữ liệu quan hệ với các bảng như hình bên dưới
Bảng NewsCategory
csdl-2.png
Bảng Users
csdl-3.jpg
Thiết lập Unique cho thuộc tính UserName (duy nhất)
csdl-4.jpg
Bảng News
csdl-5.jpg
Sơ đồ quan hệ
csdl-1.jpg
2. Thực hiện database first(EntityFramework Core) để Generate Context và các Entity Class(Domain Entities)
3. Hiển thị danh sách tin tức
- Sử dụng Action Index để điều khiển việc hiển thị dữ liệu của tin tức
        public IActionResult Index(string? searchString, int? page, string sortBy, int? categoryId)
        {
           
            IEnumerable<NewsCategory> newsCategory = newsRepository.GetAllNewsCategory();
            // Tạo SelectList từ danh sách quyền truy cập
            SelectList selectList = new SelectList(newsCategory, "Id", "CategoryName");

            // Lưu SelectList vào ViewBag để sử dụng trong View
            ViewBag.NewsCategory = selectList;
            TempData["searchString"] = searchString != null ? searchString.ToLower() : "";
            int pageSize = 3;
            int pageNumber = (page ?? 1);
            IPagedList<News> newsList = new PagedList<News>(newsRepository.GetNewsByKeyword(searchString, sortBy, categoryId), pageNumber, pageSize);
            return View(newsList);
        }
Trong đó,
+ IEnumerable<NewsCategory> newsCategory = newsRepository.GetAllNewsCategory();
Dùng để lấy thông tin tất cả danh mục nhóm tin để có thể đưa vào DropdownList để chọn danh mục nhóm tin(cboNewsCategory)
+ newsList = newsList.ToPagedList(pageNumber, pageSize);
đối tượng newsList là danh sách tin tức có sự tham gia của việc phân trang. Sử dụng library using X.PagedList
+ Các tham số truyền vào có sử dụng tìm kiếm(từ khoá và cboNewsCategory), phân trang, sắp xếp
- Tạo các INewsRepository, NewsRepository, NewsDao tương ứng
+ INewsRepository:
    public interface INewsRepository
    {
        IEnumerable<News> GetNewsByKeyword(string keyword, string sortBy, int? categoryId);
    }
+ NewsRepository:
    public class NewsRepository:INewsRepository
    {
        public IEnumerable<News> GetNewsByKeyword(string keyword, string sortBy, int? categoryId)=> NewsDao.Instance.GetNewsByKeyword(keyword, sortBy, categoryId);
    }
+ NewsDao:
        public IEnumerable<News> GetNewsByKeyword(string keyword, string sortBy, int? categoryId)
        {
            List<News> news = new List<News>();
            try
            {
                ProductMangementBatch177Context stock = new ProductMangementBatch177Context();
                IQueryable<News> newsQuery = stock.News;
                if (!String.IsNullOrEmpty(keyword))
                {
                    newsQuery = newsQuery.Where(u => u.Title != null && u.Title.ToLower().Contains(keyword)); // Remove ToList() here
                }

                switch (sortBy)
                {
                    case "title":
                        newsQuery = (Microsoft.EntityFrameworkCore.DbSet<News>)newsQuery.OrderBy(o => o.Title);
                        break;
                    case "titledesc":
                        newsQuery = (Microsoft.EntityFrameworkCore.DbSet<News>)newsQuery.OrderByDescending(o => o.Title);
                        break;
                    default:
                        break;
                }
                if (categoryId != null)
                {
                    news = newsQuery.Where(u => u.CategoryId == categoryId).ToList();
                }
                else
                {
                    news = newsQuery.ToList();
                }
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
            return news;
        }
- View Index của Controller News sẽ như thế nào?
@model IEnumerable<DatabaseFirstDemo.Models.News>
@using X.PagedList;
@using X.PagedList.Mvc.Core;
@{
    ViewData["Title"] = "Quản lý Tin tức";
    Layout = "~/Areas/Admin/Views/Shared/_Layout.cshtml";
}

<div class="row">
    <div class="col-md-12">
        <section class="panel">
            <header class="panel-heading">
                Quản lý Tin tức
            </header>
            <div class="panel-body">
                <div class="col-md-12" style="margin-top:10px">
                    <p>
                        <a class="btn btn-danger create">Tạo mới</a>
                    </p>
                    @{
                        if (TempData["AlertMessage"] != null)
                        {
                            <div id="alertBox" class="alert @TempData["Type"]">
                                @TempData["AlertMessage"]
                            </div>
                        }
                    }
                    <table class="table table-striped">
                        <thead>
                            <tr>
                                <th>
                                    @Html.DisplayNameFor(model => model.Title)
                                </th>
                                <th>
                                    @Html.DisplayNameFor(model => model.Description)
                                </th>
                                <th>
                                    @Html.DisplayNameFor(model => model.SubjectContent)
                                </th>
                                <th>
                                    @Html.DisplayNameFor(model => model.DateUpdate)
                                </th>
                                <th>
                                    @Html.DisplayNameFor(model => model.Status)
                                </th>
                                <th>
                                    @Html.DisplayNameFor(model => model.Avatar)
                                </th>
                                <th>
                                    @Html.DisplayNameFor(model => model.Category)
                                </th>
                                <th>
                                    @Html.DisplayNameFor(model => model.User)
                                </th>
                                <th></th>
                            </tr>
                        </thead>
                        <tbody>
                            @foreach (var item in Model)
                            {
                                <tr>
                                    <td>
                                        @Html.DisplayFor(modelItem => item.Title)
                                    </td>
                                    <td>
                                        @Html.DisplayFor(modelItem => item.Description)
                                    </td>
                                    <td>
                                        @Html.DisplayFor(modelItem => item.SubjectContent)
                                    </td>
                                    <td>
                                        @item.DateUpdate.ToString("dd/MM/yyyy")
                                    </td>
                                    <td>
                                        @Html.DisplayFor(modelItem => item.Status)
                                    </td>
                                    <td>
                                        @Html.DisplayFor(modelItem => item.Avatar)
                                    </td>
                                    <td>
                                        @Html.DisplayFor(modelItem => item.Category.CategoryName)
                                    </td>
                                    <td>
                                        @Html.DisplayFor(modelItem => item.User.Password)
                                    </td>
                                    <td>
                                        <button class="btn btn-danger edit" data-id="@item.Id">Sửa</button>&nbsp;
                                        <button class="btn btn-danger detail" data-id="@item.Id">Chi tiết</button>&nbsp;
                                        <a class="btn btn-danger delete" data-id="@item.Id">Xoá</a>
                                    </td>
                                </tr>
                            }
                        </tbody>
                    </table>
                    <div class="pull-right">
                        @Html.PagedListPager((IPagedList)Model, page => Url.Action("Index", new {page = page,
                        SearchString = @Context.Request.Query["SearchString"], sortby = @Context.Request.Query["sortby"]}),
                        new X.PagedList.Web.Common.PagedListRenderOptions {
                        LiElementClasses = new string[] {"page-item"},
                        PageClasses = new string[] { "page-link" }
                        })
                    </div>
                </div>
            </div>
        </section>
    </div>
</div>
Trong đó,
+ Import thư viện X.PagedList.Mvc.Core
+ Các trường dữ liệu đổ ra từ Model News, các button có các class để sử dụng jquery đọc phần tử trong HTML
+ Truyền Id vào các nút button để lấy được khoá để xử lý dữ liệu thông qua các phương thức như GET hoặc POST
+ Dòng cuối cùng thể hiện việc phân trang, kết hợp với tìm kiếm, sắp xếp
+ Còn lại, sử dụng BootStrap cho đẹp
- Kết quả được như hình bên dưới:
web-tin-tuc-1.jpg
* Chú ý: Nhớ cập nhật dữ liệu thì mới thấy được nội dung
3. Tạo mới tin tức:
- Tại View, có 1 nút tạo mới, chú ý chỗ class create, đây là class với tên là create để khi nhấn vào thì sự kiện jquery được kích hoạt
                    <p>
                        <a class="btn btn-danger create">Tạo mới</a>
                    </p>
- Thực hiện javascript sau
        $(document).on('click', '.create', function () {
            $('#modal-form').modal('show');
            $('.modal-title').text('Tạo mới tin tức');
            $('#btn-save').attr('data-action', '/Admin/News/Create');
            $('#form-news').trigger('reset');
        });
Với click này thì một popup modal-form hiển thị để người dùng có thể nhập đầy đủ thông tin vào; btn-save là id của form nhập liệu, gán action C# thực thi việc tạo mới.
- Tại View, bổ sung modal sau:
<div id="modal-form" class="modal fade">
    <div class="modal-dialog">
        <div class="modal-content">
            <div class="modal-header">
                <button type="button" class="close" data-dismiss="modal">&times;</button>
                <h4 class="modal-title"></h4>
            </div>
            <div class="modal-body">
                <form id="form-news" method="post" action="#">
                    <div class="alert alert-danger hidden" id="alert-fail"></div>
                    <div class="form-group">
                        <label for="Title">Tiêu đề</label>
                        <input type="text" class="form-control" id="Title" name="Title" placeholder="Nhập tiêu đề bài viết" required>
                    </div>
                    <div class="form-group">
                        <label for="Description">Mô tả</label>
                        <input type="text" class="form-control" id="Description" name="Description" placeholder="Nhập mô tả">
                    </div>
                    <div class="form-group">
                        <label for="SubjectContent">Nội dung</label>
                        <input type="text" class="form-control" id="SubjectContent" name="SubjectContent" placeholder="Nhập nội dung tin" required>
                    </div>
                    <div class="form-group">
                        <label for="CategoryId">Danh mục tin tức</label>
                        @Html.DropDownList("CategoryId", (SelectList)ViewBag.NewsCategory, new { @class =
                        "form-control", @id = "cboNewsCategoryId" })
                    </div>
                    <div class="form-group">
                        <label for="Avatar">Ảnh đại diện</label>
                        <input type="text" class="form-control" id="Avatar" name="Avatar" placeholder="Nhập địa chỉ ảnh đại diện" required>
                    </div>
                    <div class="form-group">
                        <label for="DateUpdate">Ngày cập nhật</label>
                        <input type="text" disabled class="form-control" id="DateUpdate" name="DateUpdate" placeholder="Nhập ngày cập nhật" required>
                    </div>
                    <div class="form-group">
                        <label for="Status">Trạng thái</label>
                        @Html.CheckBox("Status", true)
                    </div>

                    <input type="hidden" id="Id" name="Id" />
                    <input type="hidden" id="UserId" name="UserId" />
                </form>
            </div>
            <div class="modal-footer">
                <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
                <button type="submit" class="btn btn-primary" id="btn-save">Lưu lại</button>
            </div>
        </div>
    </div>
</div>
Trong đó, 
+ Id và UserId là thuộc tính ẩn, sử dụng để cập nhật dữ liệu
+ id="form-news" dùng làm khoá để xác định sự kiện nào cần thực thi, vì trong 1 trang có nhiều action chứ không riêng gì 1 action của Create hay Edit.
- Khi người dùng nhập đầy đủ thông tin, chèn thêm đoạn script sau để khi nhấn nút lưu lại, sẽ gọi sự kiện có #btn-save
       // Save news
       $(document).on('click', '#btn-save', function (event) {
           event.preventDefault();  // Chặn hành động gửi form mặc định
           var form = $('#form-news');
           var data = form.serializeArray();
           // Lấy giá trị từ các trường thuộc tính của news trong form
           // Ví dụ:
           var news = {
               Id: $('#Id').val(),
               UserId: $('#UserId').val(),
               Title: $('#Title').val(),
               Description: $('#Description').val(),
               SubjectContent: $('#SubjectContent').val(),
               Avatar: $('#Avatar').val(),
               CategoryId: $('#cboNewsCategoryId').val(),
               DateUpdate: $('#DateUpdate').val(),
               Status: $('#Status').is(':checked') // Lấy giá trị checked của trường Status
           };
           data.push({ name: 'news.Title', value: news.Title });
           data.push({ name: 'news.Description', value: news.Description });
           data.push({ name: 'news.SubjectContent', value: news.SubjectContent });
           data.push({ name: 'news.Avatar', value: news.Avatar });
           data.push({ name: 'news.CategoryId', value: news.CategoryId });
           data.push({ name: 'news.Status', value: news.Status });
           data.push({ name: 'news.Id', value: news.Id });
           data.push({ name: 'news.UserId', value: news.UserId });
           data.push({ name: 'news.DateUpdate', value: news.DateUpdate });
          
           $.ajax({
               url: $(this).data('action'),
               type: 'POST',
               data: $.param(data),
               success: function (response) {
                   if (response.success) {
                       location.reload();
                   } else {
                       $('#alert-fail').removeClass('hidden');
                       $('#alert-fail').text('Yêu cầu nhập đầy đủ thông tin');
                   }
               },
               error: function (error) {
                   console.log(error);
               }
           });
          
       });
Trong này có Id và UserId, dùng để cho phần Edit sau này
- Tiếp theo, phần Action Create sẽ mở NewsController
        public IActionResult Create()
        {
            ViewBag.NewsCategory = new SelectList(newsRepository.GetAllNewsCategory(), "Id", "CategoryName");
            return View();
        }
Đây là Action với HttpGet dùng để đổ dữ liệu lên DropdownList của NewsCategory(Danh mục loại tin tức)
        [HttpPost]
        public JsonResult Create(News news)
        {
            try
            {
                // Lấy giá trị từ các trường thuộc tính của news trong form
                var model = new News
                {
                    Title = news.Title,
                    Description = news.Description,
                    SubjectContent = news.SubjectContent,
                    CategoryId = news.CategoryId,
                    Avatar = news.Avatar,
                    Status = news.Status
                };
                model.DateUpdate = Common.Common.GetServerDateTime();
                var user = User as ClaimsPrincipal;
                var userName = user?.FindFirstValue(ClaimTypes.Name);
                model.UserId = userRepository.GetByUserName(userName).UserId;
                newsRepository.Insert(model);

                SetAlert("Insert Data is success!", "success");

                /* }*/
            }
            catch (Exception ex)
            {
                return Json(new { success = false, message = ex.Message });
            }
            return Json(new { success = true });
        }
Trong đó, 
+ Common.Common.GetServerDateTime() nhận thời gian hiện tại
        public static DateTime GetServerDateTime()
        {
            return DateTime.Now.ToUniversalTime().AddHours(7);
        }
+ var user = User as ClaimsPrincipal;
Dòng này chuyển đổi đối tượng User thành kiểu ClaimsPrincipal và gán cho biến user. Đối tượng User đại diện cho người dùng đã xác thực hiện tại trong ứng dụng.
+ var userName = user?.FindFirstValue(ClaimTypes.Name);
Dòng này lấy giá trị của claim Name từ đối tượng user. Claim Name thường đại diện cho tên hoặc tên người dùng của người dùng. Phương thức FindFirstValue được sử dụng để tìm kiếm claim đầu tiên với loại claim được chỉ định và trả về giá trị của nó. Toán tử ? được sử dụng để kiểm tra null, điều này có nghĩa là nếu đối tượng user là null, phương thức FindFirstValue sẽ không được gọi và userName sẽ được gán giá trị null.
+ model.UserId = userRepository.GetByUserName(userName).UserId;
Dòng này gán thuộc tính UserId của đối tượng model với ID người dùng được lấy từ userRepository dựa trên userName. Nó giả định rằng userRepository có một phương thức có tên GetByUserName nhận một tên người dùng làm tham số và trả về một đối tượng người dùng với thuộc tính UserId.
web-tin-tuc-2.jpg
5. Cập nhật tin tức
- Vẫn sử dụng Form modal Create nhưng thêm đoạn script mới về sự kiện .edit như sau:
 
       $(document).on('click', '.edit', function () {
            var id = $(this).data('id');
            $.get('/Admin/News/Edit', { id: id })
                .done(function (response) {
                    if (response.success) {
                        $('#modal-form').modal('show');
                        $('.modal-title').text('Chỉnh sửa tin tức');
                        $('#btn-save').attr('data-action', '/Admin/News/Edit');
                        $('#Id').val(response.data.id);
                        $('#Title').val(response.data.title);
                        $('#Description').val(response.data.description);
                        $('#SubjectContent').val(response.data.subjectContent);
                        $('#Avatar').val(response.data.avatar);
                        $('#cboNewsCategoryId').val(response.data.categoryId);
                        $('#DateUpdate').val(response.data.dateUpdate);
                        $('#UserId').val(response.data.userId);                   
                        $('#Status').prop('checked', response.data.status);
                    } else {
                        alert(response.message);
                    }
                })
                .fail(function (error) {
                    console.log(error);
                });
        });
- Tại Action Edit trong NewsController thêm mới đoạn code sau:
        [HttpGet]
        public IActionResult Edit(int id)
        {
            News news = newsRepository.GetById(id);
            ViewBag.NewsCategory = new SelectList(newsRepository.GetAllNewsCategory(), "Id", "CategoryName");
            var data = new
            {
                Id = id,
                Title = news.Title,
                Description = news.Description,
                SubjectContent = news.SubjectContent,
                CategoryId = news.CategoryId,
                DateUpdate = news.DateUpdate.ToString("dd/MM/yyyy"),
                Avatar = news.Avatar,
                Status = news.Status,
                UserId = news.UserId,
            };

            return new JsonResult(new { success = true, data = data });
        }
Trong đó, Phương thức HttpGet để đổ dữ liệu lên Form Edit thông qua kết quả trả về là đối tượng data(đoạn code javascript trên sẽ nhận và đẩy vào form Modal)
        [HttpPost]
        public JsonResult Edit(News news)
        {
            try
            {
                // Lấy giá trị từ các trường thuộc tính của news trong form
                var newp = new News
                {
                    Id = news.Id,
                    Title = news.Title,
                    Description = news.Description,
                    SubjectContent = news.SubjectContent,
                    CategoryId = news.CategoryId,
                    Avatar = news.Avatar,
                    Status = news.Status,
                    UserId = news.UserId,
                };
                if (news.DateUpdate != null)
                {
                    newp.DateUpdate = DateTime.ParseExact(news.DateUpdate.ToString("dd/MM/yyyy"), "dd/MM/yyyy", null);
                }
                newsRepository.Update(newp);
                SetAlert("Update Data is success!", "success");
            }
            catch (Exception ex)
            {
                return Json(new { success = false, message = ex.Message });
            }
            return Json(new { success = true });
        }
Trong đó, phương thức HttpPost dùng để thực thi việc cập nhật dữ liệu
+ newp.DateUpdate = DateTime.ParseExact(news.DateUpdate.ToString("dd/MM/yyyy"), "dd/MM/yyyy", null);
Dòng code này sẽ định dạng lại ngày tháng năm cho đúng để lưu vào SQL
web-tin-tuc-3.jpg



Nguồn bài viết: DOTNET.VN

BÌNH LUẬN BÀI VIẾT

Bài viết mới nhất

LIKE BOX

Bài viết được xem nhiều nhất

HỌC HTML