Tích hợp Text Editor SummerNote vào View Razor Asp.Net MVC


28/02/2020- duocnt    3833 Views    


Các bước thực hiện:

                  1. Tạo Database đơn giản với 1 table (Post).
                  2. Tạo project Asp.Net MVC.
                  3. Tạo folder "postedImage" trong project.
                  4. Generate Entity Model từ Database đã tạo trước đó.
                  5. Tạo Controller (Post).
                  6. Tạo phương thức uploadFile() trong controller (Post).
                  7. Tạo 2 ActionResult createpost() (1 dành cho HttpGet và 1 dành cho HttpPost).
                  8. Tao View createpost.cshtml.
                  9. Tạo các phương thức callBack jQuery và tích hợp SummerNote vào View.
                  10. Kiểm tra tính năng.
                  11. Kết luận.
                  12. Video clip.

                  Tài liệu tham khảo.

                  Tại đây.

                  Sau khi tích hợp, View sẽ như hình:

                  Thực hiện:

                  1 - Tạo Database đơn giãn với 1 table (Table Post).


                  2 - Tạo project Asp.Net MVC.

                  Các bước tạo 1 project Asp.net MVC khá đơn giãn, nên trong bài viết này sẽ không hướng dẫn chi tiết.

                  3 - Tạo Folder "postedImage" trong project.


                  4 - Generate Entity Model từ Database đã tạo ở trên.

                   - Right-click lên folder Models trong project => Add = >  New Item...


                   - Chọn ADO.NET Entity Data Model.


                   - Chọn "Code First from da..." trong cửa sổ "Entity Data Model Wizard".


                   - Click "New Connection...".


                  - Nhập các thông số để kết nối tới SQL Server và chọn Database cần kết nối.


                   - Click Next để tiếp tục.

                   - Chọn table muốn tạo Entity Model (ở đây là table Post), lưu ý không chọn "sysdiagrams", click "Finish".


                  5 - Tạo controller Post.


                  6 - Tạo phương thức "uploadFile()" trong PostController.

                  [HttpPost]
                          public JsonResult UploadFile(HttpPostedFileBase uploadedFiles)
                          {
                              string returnImagePath = string.Empty;
                              string fileName;
                              string Extension;
                              string imageName;
                              string imageSavePath;
                   
                              if (uploadedFiles.ContentLength > 0)
                              {
                                  fileName = Path.GetFileNameWithoutExtension(uploadedFiles.FileName);
                                  Extension = Path.GetExtension(uploadedFiles.FileName);
                                  imageName = fileName + DateTime.Now.ToString("yyyyMMddHHmmss");
                                  imageSavePath = Server.MapPath("/postedImage/") + imageName + Extension;
                                  uploadedFiles.SaveAs(imageSavePath);
                                  returnImagePath = "/postedImage/" + imageName + Extension;               
                              }
                   
                              return Json(Convert.ToString(returnImagePath), JsonRequestBehavior.AllowGet);
                          }


                  7 - Tạo 2 ActionResult createpost() , dành cho HttpGet và 1 dành cho HttpPost.


                          [HttpGet]
                          public ActionResult createpost()
                          {
                              return View();
                          }
                   
                          [HttpPost]
                          [ValidateInput(false)]
                          public ActionResult createpost(Post entity)
                          {
                              db = new hocsummernoteDb();
                              db.Posts.Add(entity);
                              db.SaveChanges();
                              return View();
                          }


                  8 - Tạo View createpost.cshtml.

                    - Right-click vào ActionResult createpost() => Add View



                   - Chọn các thông số cho View như hình.


                   - View được tạo nguyên bản sẽ như sau.

                  @model HocSummerNote.Models.Post
                   
                  @{
                      ViewBag.Title = "createpost";
                      Layout = "~/Views/Shared/_Layout.cshtml";
                  }
                  <h2>createpost</h2>
                  @using (Html.BeginForm())
                  {
                      @Html.AntiForgeryToken()
                     
                      <div class="form-horizontal">
                          <h4>Post</h4>
                          <hr />
                          @Html.ValidationSummary(true, "", new { @class = "text-danger" })
                          <div class="form-group">
                              @Html.LabelFor(model => model.Title, htmlAttributes: new { @class = "control-label col-md-2" })
                              <div class="col-md-10">
                                  @Html.EditorFor(model => model.Title, new { htmlAttributes = new { @class = "form-control" } })
                                  @Html.ValidationMessageFor(model => model.Title, "", new { @class = "text-danger" })
                              </div>
                          </div>
                   
                          <div class="form-group">
                              @Html.LabelFor(model => model.Metatitle, htmlAttributes: new { @class = "control-label col-md-2" })
                              <div class="col-md-10">
                                  @Html.EditorFor(model => model.Metatitle, new { htmlAttributes = new { @class = "form-control" } })
                                  @Html.ValidationMessageFor(model => model.Metatitle, "", new { @class = "text-danger" })
                              </div>
                          </div>
                   
                          <div class="form-group">
                              @Html.LabelFor(model => model.ShortInfo, htmlAttributes: new { @class = "control-label col-md-2" })
                              <div class="col-md-10">
                                  @Html.EditorFor(model => model.ShortInfo, new { htmlAttributes = new { @class = "form-control" } })
                                  @Html.ValidationMessageFor(model => model.ShortInfo, "", new { @class = "text-danger" })
                              </div>
                          </div>
                   
                          <div class="form-group">
                              @Html.LabelFor(model => model.Content, htmlAttributes: new { @class = "control-label col-md-2" })
                              <div class="col-md-10">
                                  @Html.EditorFor(model => model.Content, new { htmlAttributes = new { @class = "form-control" } })
                                  @Html.ValidationMessageFor(model => model.Content, "", new { @class = "text-danger" })
                              </div>
                          </div>
                   
                          <div class="form-group">
                              @Html.LabelFor(model => model.PostedDate, htmlAttributes: new { @class = "control-label col-md-2" })
                              <div class="col-md-10">
                                  @Html.EditorFor(model => model.PostedDate, new { htmlAttributes = new { @class = "form-control" } })
                                  @Html.ValidationMessageFor(model => model.PostedDate, "", new { @class = "text-danger" })
                              </div>
                          </div>
                   
                          <div class="form-group">
                              @Html.LabelFor(model => model.Active, htmlAttributes: new { @class = "control-label col-md-2" })
                              <div class="col-md-10">
                                  <div class="checkbox">
                                      @Html.EditorFor(model => model.Active)
                                      @Html.ValidationMessageFor(model => model.Active, "", new { @class = "text-danger" })
                                  </div>
                              </div>
                          </div>
                   
                          <div class="form-group">
                              <div class="col-md-offset-2 col-md-10">
                                  <input type="submit" value="Create" class="btn btn-default" />
                              </div>
                          </div>
                      </div>
                  }
                   
                  <div>
                      @Html.ActionLink("Back to List", "Index")
                  </div>
                   
                  @section Scripts {
                      @Scripts.Render("~/bundles/jqueryval")
                  }


                   - View lên trình duyệt sẽ có giao diện như sau.


                   - Chúng ta cần bỏ đi những textbox không cần hiển thị trên giao diện như "Metatitle", "PostedDate".

                   - Tích hợp SummerNote Text Editor vào "Content".

                   - Vào View, tìm thẻ  "@Html.EditorFor(model => model.Content....", đổi thành "@Html.TextAreaFor(model => model.Content ..", và gắn class "content-editor" vào cho thẻ này.

                  <div class="form-group">
                      @Html.LabelFor(model => model.Content,htmlAttributes: new { @class= "control-label col-md-2" })
                      <div class="col-md-10">
                           @Html.TextAreaFor(model => model.Content, new { @class = "form-control content-editor" })
                           @*@Html.EditorFor(model=> model.Content, new { htmlAttributes = new { @class ="form-control" } })*@
                           @Html.ValidationMessageFor(model =>model.Content, "", new { @class= "text-danger" })
                      </div>
                  </div>


                  9 - Tạo phương thức callBacks jQuery và tích hợp SummerNote vào View.

                   - Trong @section Scripts , link 2 thư viện css và js của SummerNote.

                  <!--
                  include summernote css/js -->
                  <link href="http://cdnjs.cloudflare.com/ajax/libs/summernote/0.8.12/summernote.css" rel="stylesheet">
                  <script src="http://cdnjs.cloudflare.com/ajax/libs/summernote/0.8.12/summernote.js"></script>

                   - Viết phương thức uploadImage(), phương thức này được gọi trong hàm callBacks() của SummerNote sau khi thực hiện thao tác chọn hình.

                          function uploadImage(file) {
                              var formData = newFormData();
                              formData.append("uploadedFiles", file);
                              $.ajax({
                                  data: formData,
                                  type: "POST",
                                  url: '/Post/UploadFile',
                                  cache: false,
                                  contentType: false,
                                  processData: false,
                                  success: function (FileUrl) {
                                      alert(FileUrl);
                                      var imgNode = document.createElement('img');
                                      imgNode.src = FileUrl;
                                      $('.content-editor').summernote('insertNode', imgNode);
                                  },
                                  error: function (data) {
                                      alert(data.responseText);
                                  }
                              });
                          }

                   - Tích hợp SummerNote vào Textbox "Content" 

                        $(document).ready(function () {
                              $(".content-editor").summernote({
                                  height: 300,
                                  minHeight: null,
                                  maxHeight: null,
                                  codemirror: {
                                      theme: "monokai"
                                  },
                                  callbacks: {
                                      onImageUpload: function (files) {
                                          for (var i = 0; i < files.length; i++) {
                                                                          uploadImage(files[i]);
                                          }
                                      }
                                  },
                                  fontSizes: ['12', '14', '16', '18', '24', '36', '48'],
                                  toolbar: [
                                        ['style', ['style']],
                                        ['font', ['bold', 'underline', 'clear']],
                                        ['fontname', ['fontname']],
                                        ['fontsize', ['fontsize']],
                                        ['color', ['color']],
                                        ['para', ['ul', 'ol', 'paragraph']],
                                        ['table', ['table']],
                                        ['insert', ['link', 'picture', 'video']],
                                        ['view', ['fullscreen', 'codeview', 'help']],
                                  ],
                              });
                          });

                   - Code jQuery đầy đủ trong @section Scripts .

                  @section Scripts {
                      @Scripts.Render("~/bundles/jqueryval")
                      <!-- include summernote css/js -->
                      <link href="http://cdnjs.cloudflare.com/ajax/libs/summernote/0.8.12/summernote.css" rel="stylesheet">
                      <script src="http://cdnjs.cloudflare.com/ajax/libs/summernote/0.8.12/summernote.js"></script>
                      <script type="text/javascript">
                          $(document).ready(function () {
                              $(".content-editor").summernote({
                                  height: 300,
                                  minHeight: null,
                                  maxHeight: null,
                                  codemirror: {
                                      theme: "monokai"
                                  },
                                  callbacks: {
                                      onImageUpload: function (files) {
                                          for (var i = 0; i < files.length; i++) {
                                                                          uploadImage(files[i]);
                                          }
                                      }
                                  },
                                  fontSizes: ['12', '14', '16', '18', '24', '36', '48'],
                                  toolbar: [
                                        ['style', ['style']],
                                        ['font', ['bold', 'underline', 'clear']],
                                        ['fontname', ['fontname']],
                                        ['fontsize', ['fontsize']],
                                        ['color', ['color']],
                                        ['para', ['ul', 'ol', 'paragraph']],
                                        ['table', ['table']],
                                        ['insert', ['link', 'picture', 'video']],
                                        ['view', ['fullscreen', 'codeview', 'help']],
                                  ],
                              });
                          });
                          function uploadImage(file) {
                              var formData = new FormData();
                              formData.append("uploadedFiles", file);
                              $.ajax({
                                  data: formData,
                                  type: "POST",
                                  url: '/Post/UploadFile',
                                  cache: false,
                                  contentType: false,
                                                  processData: false,
                                  success: function (FileUrl) {
                                      alert(FileUrl);
                                      var imgNode = document.createElement('img');
                                      imgNode.src = FileUrl;
                                      $('.content-editor').summernote('insertNode', imgNode);
                                  },
                                  error: function (data) {
                                      alert(data.responseText);
                                  }
                              });
                          }
                      </script>
                  }


                   - Sau khi tích hợp SummerNote, view lên trình duyệt.

                  10 - Kiểm tra tính năng.

                   - Chọn hình để insert vào bài viết.

                   - Sau khi chọn hình từ PC, hình sẽ được view vào Content và đồng thời hình được lưu vào folder postedImage do phương thức callBacks() của SummerNote.


                   - Khi click Create và kiểm tra Database, dữ liệu sẽ được lưu bằng đường dẫn file hình.


                  11 - Kết luận.

                   - Nếu chúng ta không customize lại phương thức callBacks onImageUpload của SummerNote, khi chọn hình để Insert vào bài viết, hình sẽ được mã hóa thành string Base64 và lưu toàn bộ vào Database. Như vậy sẽ làm cho Database tăng dung lượng nhanh chóng, và rất khó để hiển thị lại hình ảnh lên view.

                   - Vậy là chúng ta đã hoàn thành công việc tích hợp Text Editor SummerNote vào Web Asp.Net MVC.

                   - Trong quá trình thực hiện, nếu xảy ra lỗi hoặc chương trình không tích hợp được SummerNote, các bạn đừng ngần ngại comment vào bên dưới bài viết hoặc gởi mail về email trong phần thông tin liên hệ dưới footer.

                  - Chúc các bạn thành công.

                  12 - Video Clip.


                  Góp ý kiến

                  ;
                  ;