C# Cơ bản .NET Core §1 Cài đặt, chương trình C# đầu tiên §2 Biến, kiểu dữ liệu và nhập/xuất §3 Toán tử số học và gán §4 So sánh, logic và lệnh if, switch §5 Vòng lặp for, while §6 Phương thức - Method §7 Phương thức - Delegate §8 Lớp - Class §9 Namespace §10 Partial, Nested §11 Kiểu giá trị, tham chiếu §12 Kiểu vô danh và dynamic §13 Biểu thức lambda §14 Event §15 Hàm hủy - Quá tải toán tử - thành viên tĩnh - indexer §16 null và nullable §17 Mảng §18 Chuỗi ký tự §19 Tính kế thừa §20 Phương thức khởi tạo §21 Tính đa hình - abstract - interface §22 Struct và Enum §23 Ngoại lệ Exeption §24 IDisposable - using §25 File cơ bản §26 FileStream §27 Generic §28 Collection - List §29 SortedList §30 Queue / Stack §31 Linkedlist §32 Dictionary - HashSet §33 Phương thức mở rộng §34 ObservableCollection §35 LINQ §36 (Multithreading) async - bất đồng bộ §37 Type §38 Attribute Annotation §39 DI Dependency Injection §40 (Multithreading) Parallel §41 Thư viện lớp §42 (Networking) HttpClient §43 (Networking) HttpMessageHandler §44 (Networking) HttpListener §45 (Networking) Tcp TcpListenerr/TcpClient §46 (ADO.NET) SqlConnection §47 (ADO.NET) SqlCommand §48 (EF Core) Tổng quan §49 (EF Core) Tạo Model §50 (EF Core) Fluent API §51 (EF Core) Query §52 (EF Core) Scaffold §53 (EF Core) Migration §54 (ASP.NET CORE) Hello World! §55 (ASP.NET CORE) Middleware §56 (ASP.NET CORE) Map - Request - Response §57 (ASP.NET CORE) IServiceCollection - MapWhen §58 (ASP.NET CORE) Session - ISession §59 (ASP.NET CORE) Configuration §60 (ASP.NET CORE) Gửi Mail §61 (ASP.NET CORE) SASS/SCSS §62 (ASP.NET CORE) LibMan §63 (ASP.NET RAZOR) Khởi tạo và Route §64 (ASP.NET RAZOR) Cú pháp Razor §65 (ASP.NET RAZOR) Layout trong ASP.NET Core §66 (ASP.NET RAZOR) Partial §67 (ASP.NET RAZOR) ViewComponent §68 (ASP.NET RAZOR) TagHelper §69 (ASP.NET RAZOR) PageModel §70 (ASP.NET RAZOR) Model Binding §71 (ASP.NET RAZOR) HTML Form, Validation §72 (ASP.NET RAZOR) Upload File §73 (ASP.NET RAZOR) HtmlHelper §74 (ASP.NET RAZOR) Entity Framework §75 (ASP.NET RAZOR) Paging §76 (ASP.NET RAZOR) Identity (1) - Register, Login, Logout §77 (ASP.NET RAZOR) Identity (2) Lockout, Reset Password §78 (ASP.NET RAZOR) Identity (3) Google Login §79 (ASP.NET RAZOR) Identity (4) Facebook Login §80 (ASP.NET RAZOR) Identity (5) profile, password, email ... §81 (ASP.NET RAZOR) Identity (6) Role §82 (ASP.NET RAZOR) Identity (7) Role-based Authorization §83 (ASP.NET RAZOR) Identity (8) RoleClaim §84 (ASP.NET RAZOR) Identity (9) Authorization Handler §85 (ASP.NET RAZOR) IAuthorizationService §86 (ASP.NET MVC) Controller - View §87 (ASP.NET MVC) Route §88 (ASP.NET MVC) EF, Identity §89 (ASP.NET MVC) Binding, Validation §90 (ASP.NET MVC) Xây dựng Website(1) §91 (ASP.NET MVC) Xây dựng Website(2) §92 (ASP.NET MVC) Xây dựng Website(3) §93 (ASP.NET MVC) Xây dựng Website(4) §94 (ASP.NET MVC) Giỏ hàng - Cart (5) §95 (ASP.NET MVC) elFinder (5) §96 (ASP.NET MVC) SB Admin (6)

Bài thực hành này tiếp tục trên ví dụ cũ mvcblog: Xây dựng ứng dụng mẫu - Danh mục của Blog (phần 1), tải mã nguồn về mở ra tiếp tục phát triển ex068-category

Tích hợp Summernote - HTML Editor vào Website

Có nhiều công cụ soạn thảo HTML (WYSIWYG Editor) để bạn tích hợp vào website, phổ biến như CkEditor, Summernote, TinyMCE ... Ở đây sẽ sử dụng công cụ đơn giản là Summernote, công cụ này có sử dụng BootStrap, JQuery.

Tải về bản mới tại Summernote Releases, ví dụ tải về file summernote-0.8.18-dist.zip. Giải nén, copy tất cả các file có vào thư mục của dự án, ta sẽ copy vào thư mục wwwroot/summernote - để có thể truy cập qua file tĩnh ASP.NET MVC

Trong thư mục wwwroot/summernote có nhiều file .js, .css tùy ngữ cảnh mà sử dụng. Trong trường hợp sử dụng cùng CSS BootStrap, thì cần nạp vào trang HTML hai file:

<script src="@Url.Content("~/summernote/summernote-bs4.js")"></script>
<link href="@Url.Content("~/summernote/summernote-bs4.min.css")" rel="stylesheet">

Sau đó kích hoạt phần tử HTML nào trở thành Editor bằng cú pháp mã JavaScript như sau:

<script>
    $(document).ready(function() {
        $('#htmlelementid').summernote({
            height: 200,
            toolbar: [
                ['style', ['bold', 'italic', 'underline', 'clear']],
                ['font', ['strikethrough', 'superscript', 'subscript']],
                ['fontsize', ['fontsize']],
                ['color', ['color']],
                ['para', ['ul', 'ol', 'paragraph']],
                ['height', ['height']]
            ]
        });
    });
</script>

Trong đoạn mã trên thì:

  • #htmlelementid là selector chọn phần tử HTML sẽ là Editor (bạn có thể thay bằng phần tử của bạn theo cú pháp chọn phần tử trong CSS, JS xem chọn phần tử HTML ) , thường dùng loại phần tử <textarea>
  • height: 200 thiết lập chiều cao Editor
  • toolbar: [] thiết lập các công cụ

Ngoài ra các thiết lập, tùy biến nâng cao tham khảo tại: deep-dive

Áp dụng:

Trong ứng dụng của Blog, các Category có thuộc tính Content, thuộc tính này sẽ thiết lập có nội dung là HTML, do vậy khi soạn thảo, tạo mới hãy kích hoạt Summernote để biên tập nội dung HTML

Mở file Areas/Admin/Views/Category/Edit.cshtml thêm vào đoạn mã kích hoạt Summernote cho phần tử Content - nó thành như sau:

@model mvcblog.Models.Category

@{
    ViewData["Title"] = "Edit";
    Layout = "_Layout";
}

<h1>Edit</h1>

<h4>Blog Category</h4>
<hr />
<div class="row">
    <div class="col-md-8">
        <form asp-action="Edit">
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
            <input type="hidden" asp-for="Id" />
            <div class="form-group">
                <label asp-for="ParentId" class="control-label"></label>
                <select asp-for="ParentId" class="form-control" asp-items="ViewBag.ParentId"></select>
                <span asp-validation-for="ParentId" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Title" class="control-label"></label>
                <input asp-for="Title" class="form-control" />
                <span asp-validation-for="Title" class="text-danger"></span>
            </div>
            <!--Sử dụng textarea nhập dữ liệu cho Content-->
            <div class="form-group">
                <label asp-for="Content" class="control-label"></label>
                <textarea asp-for="Content" class="form-control"></textarea>
                <span asp-validation-for="Content" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Slug" class="control-label"></label>
                <input asp-for="Slug" class="form-control" />
                <span asp-validation-for="Slug" class="text-danger"></span>
            </div>
            <div class="form-group">
                <input type="submit" value="Lưu lại" class="btn btn-primary" />
            </div>
        </form>
    </div>
</div>

<div>
    <a asp-action="Index">Quay lại danh sách</a>
</div>

<!--Kích hoạt phần tử #Content là Editor HTML -->
<script src="@Url.Content("~/summernote/summernote-bs4.js")"></script>
<link href="@Url.Content("~/summernote/summernote-bs4.min.css")" rel="stylesheet">

<script>
    $(document).ready(function() {
        $('#Content').summernote({
            height: 200,
            toolbar: [
                // [groupName, [list of button]]
                ['style', ['bold', 'italic', 'underline', 'clear']],
                ['font', ['strikethrough', 'superscript', 'subscript']],
                ['fontsize', ['fontsize']],
                ['color', ['color']],
                ['para', ['ul', 'ol', 'paragraph']],
                ['height', ['height']]
                ]
        });
    });
</script>

Kết quả khi soạn thảo một Category

Có thể làm một cách tương tự khi tạo mới Category. Hoặc tạo ra một Partial để dùng lại nhiều lần

Tạo Partial Summernote

Để dùng lại nhiều lần bạn có thể tạo ra một Partial như sau:

Views/Shared/_Summernote.cshtml

@model dynamic
@{
    int height = Model.height ?? 200;
    string selector = Model.selector;
}
  
<script src="@Url.Content("~/summernote/summernote-bs4.js")"></script>
<link href="@Url.Content("~/summernote/summernote-bs4.min.css")" rel="stylesheet">

<script>
    $(document).ready(function() {
        $('@selector').summernote({
            height: @height,
            toolbar: [
                // [groupName, [list of button]]
                ['style', ['bold', 'italic', 'underline', 'clear']],
                ['font', ['strikethrough', 'superscript', 'subscript']],
                ['fontsize', ['fontsize']],
                ['color', ['color']],
                ['para', ['ul', 'ol', 'paragraph']],
                ['height', ['height']]
                ]
        });
    });
</script>

Với Partial Summernote trên, khi nào cần chèn bạn thực hiện (ví dụ tên phần tử cần kích hoạt có id là "#abc", Editor sẽ có chiều cao 200)

@await Html.PartialAsync("_Summernote", new {height = 200, selector = "#abc"})

Áp dụng: mở file Areas/Admin/Views/Category/Create.cshtml

Thêm vào cuối

@section Scripts
{
    @await Html.PartialAsync("_Summernote", new {height = 200, selector = "#Content"})
}

Kết quả:

Mã nguồn tham khảo ASP_NET_CORE/mvcblog, hoặc tải về bản bài này ex068-summernote

Đăng ký theo dõi ủng hộ kênh