How To Implement CKEditor In ASP.NET MVC

Introduction

What is CKEditor?

CkEditor is a ready-for-use HTML text editor, which is designed to simplify Web content creation.The best Browser-based rich text editors are usually called WYSIWYG editors. It is very easy to use in any type of project.
 
In this article, we are going to learn how to implement CKEditor in ASP.NET MVC. In this example, we will cover how to use it, how to post a simple blog or article & how to retrive the data from the database.

Here, I am going to use just three tables as Technology (used to retrive Id of technology), Users (used to retrive the users information), and UserPost (used to retrive the article details).

Step 1

First, I am going to create tables by using the script given below.
  1. SET ANSI_NULLS ON  
  2. GO  
  3. SET QUOTED_IDENTIFIER ON  
  4. GO  
  5. CREATE TABLE [dbo].[Technology](  
  6.     [Id] [bigint] IDENTITY(1,1) NOT NULL,  
  7.     [Technology] [nvarchar](500) NULL,  
  8.  CONSTRAINT [PK_Technology] PRIMARY KEY CLUSTERED   
  9. (  
  10.     [Id] ASC  
  11. )WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]  
  12. ) ON [PRIMARY]  
  13. GO  
  14.   
  15. SET ANSI_NULLS ON  
  16. GO  
  17. SET QUOTED_IDENTIFIER ON  
  18. GO  
  19. CREATE TABLE [dbo].[Users](  
  20.     [Id] [bigint] IDENTITY(1,1) NOT NULL,  
  21.     [FirstName] [nvarchar](100) NOT NULL,  
  22.     [LastName] [nvarchar](100) NOT NULL,  
  23.     [Email] [nvarchar](50) NOT NULL,  
  24.     [Mobile] [nvarchar](50) NULL,  
  25.  CONSTRAINT [PK_Users] PRIMARY KEY CLUSTERED   
  26. (  
  27.     [Id] ASC  
  28. )WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]  
  29. ) ON [PRIMARY]  
  30. GO  
  31.   
  32. SET ANSI_NULLS ON  
  33. GO  
  34. SET QUOTED_IDENTIFIER ON  
  35. GO  
  36. CREATE TABLE [dbo].[UserPost](  
  37.     [Id] [bigint] IDENTITY(1,1) NOT NULL,  
  38.     [UserId] [bigint] NOT NULL,  
  39.     [TechnologyId] [bigint] NOT NULL,  
  40.     [Title] [nvarchar](200) NOT NULL,  
  41.     [Description] [nvarchar](500) NULL,  
  42.     [Contents] [nvarchar](max) NOT NULL,  
  43.     [CreationDate] [datetime] NULL,  
  44.   CONSTRAINT [PK_UserPost] PRIMARY KEY CLUSTERED   
  45. (  
  46.     [Id] ASC  
  47. )WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]  
  48. ) ON [PRIMARY]  
  49. GO 
Step 2

Create an empty MVC project by using Visual Studio. Download the latest version CKEditor from here  & add the folder into the Application.

 



Step 3

I am going to use font-awesome css, bootstrap css, bootstrap js & ckeditor.js. Add all the references into a BundleConfig file, as given below. 
  1. public static void RegisterBundles(BundleCollection bundles)  
  2.         {            
  3.             bundles.Add(new ScriptBundle("~/bundles/headerJS").Include(  
  4.                         "~/Scripts/External/jquery.min.js",  
  5.                         "~/Scripts/External/bootstrap.min.js",  
  6.                         "~/Scripts/ckeditor/ckeditor.js",  
  7.                         "~/Scripts/ckeditor/samples/js/sample.js"  
  8.                         ));  
  9.               
  10.             bundles.Add(new StyleBundle("~/Content/css").Include(  
  11.                "~/Content/css/bootstrap.min.css",  
  12.                "~/Content/css/custom.css",  
  13.                "~/Content/css/font-awesome.css",  
  14.                "~/images/favico.ico",  
  15.                "~/Content/css/bootstrap-datetimepicker.min.css"  
  16.                        ));  
  17.   
  18.             bundles.Add(new ScriptBundle("~/bundles/footer").Include(  
  19.                       "~/Scripts/External/jquery.min.js",  
  20.                       "~/Scripts/External/bootstrap.min.js",  
  21.                       "~/Scripts/External/bootstrap-datepicker.js",  
  22.                       "~/Scripts/External/bootstrap-datetimepicker.min.js",  
  23.                       "~/Scripts/Custom/Shared/Layout.js"  
  24.                       ));  
  25.   
  26.         } 
Now, add the reference of above headerJS, CSS, footer into a _Layout.cstml.
 
Step 4

Create a view model ContributeViewModel, which conatins some properties, as given below.
  1. public class ContributeViewModel  
  2.     {  
  3.         public long UserId { getset; }  
  4.         public string TechnologyId { getset; }  
  5.         public string Title { getset; }  
  6.         public DateTime Date { getset; }  
  7.         public string Description { getset; }  
  8.         public string Contents { getset; }  
  9.     } 
Step 5

Now, create controller Contribute, where action method Contribute() will return a View, which will take user inputs like article title, article description, technology name, and Content by using an editor.  For technology names, we are using checkboxes.

On submit button we are going to save these data into a database by using repository pattern. Read my article  for reference of CRUD operation using repository pattern unit of work,
  1. @model CoderFunda.ViewModel.Contribute.ContributeViewModel  
  2. <div class="mainContent">  
  3.     <div class="col-sm-12"><span class="pageText1">Contribute your </span><span class="pageText2">Blog</span></div>  
  4.     <div class="col-sm-12">  
  5.         <div class="col-sm-12 col-md-6">  
  6.             <dl class="dl-horizontal dlCustom">  
  7.                 <dt>@Html.LabelFor(x => x.Title) :</dt>  
  8.                 <dd>  
  9.                     @Html.TextBoxFor(x => x.Title, new { @class = "form-control", @placeholder = "Enter Title" })  
  10.                 </dd>  
  11.                 <dt>@Html.LabelFor(x => x.TechnologyId,"Techonlogy") :</dt>  
  12.                 <dd>  
  13.                     <div class="checkbox customCheckbox" id="chkTech">  
  14.                         <label>  
  15.                             <input type="checkbox" name="blankCheckbox" id="blankCheckbox" value="Asp.NET">ASP.NET  
  16.                         </label>  
  17.                         <label>  
  18.                             <input type="checkbox" name="blankCheckbox" id="blankCheckbox" value="C#">C#  
  19.                         </label>  
  20.                         <label>  
  21.                             <input type="checkbox" name="blankCheckbox" id="blankCheckbox" value="MVC">MVC  
  22.                         </label>  
  23.                         <label>  
  24.                             <input type="checkbox" name="blankCheckbox" id="blankCheckbox" value="SQL">SQL  
  25.                         </label>  
  26.                         <label>  
  27.                             <input type="checkbox" name="blankCheckbox" id="blankCheckbox" value="Other">Other  
  28.                         </label>  
  29.                     </div>  
  30.                     <label id="lblContributeTechErrorMsg" style="display:none;color:red"></label>  
  31.                 </dd>  
  32.             </dl>  
  33.         </div>  
  34.         <div class="col-sm-12 col-md-6">  
  35.             <dl class="dl-horizontal dlCustom">  
  36.                 <dt>@Html.LabelFor(x => x.Description) :</dt>  
  37.                 <dd>@Html.TextAreaFor(x => x.Description, new { @class = "form-control", @placeholder = "Description" })</dd>  
  38.             </dl>  
  39.         </div>  
  40.         <div class="col-sm-12">  
  41.             <dl class="dl-horizontal">  
  42.                 <dt>@Html.LabelFor(x => x.Contents) :</dt>  
  43.                 <dd>  
  44.                     <div id="editor">  
  45.                     </div>  
  46.                     <label id="lblContributeContentErrorMsg" style="display:none;color:red"></label>  
  47.                 </dd>  
  48.             </dl>  
  49.             <div class="text-center">  
  50.                 <a href="@Url.Action("Home","Account")" class="customSubmit">BACK</a>  
  51.                 <input type="button" class="customPurple btnSubmit" id="btnSubmit" value="SUBMIT">  
  52.             </div>  
  53.         </div>  
  54.     </div>  
  55.     <div class="clearfix"></div>  
  56. </div> 
Now, write the code on submit button, click event, which will execute an action method using AJAX call in JavaScript, as given below. 
  1. $('.btnSubmit').click(function () {  
  2.     if (ValidateContribute()) {  
  3.         var Title = $("#Title").val();  
  4.         var TechnologyId = "";  
  5.         $('input[name="blankCheckbox"]:checked').each(function () {  
  6.             if (this.value != '')  
  7.                 TechnologyId = this.value;  
  8.         });  
  9.   
  10.         var Description = $("#Description").val();  
  11.         var Content = CKEDITOR.instances['editor'].getData();  
  12.         var ContributeModel = {  
  13.             Title: Title,  
  14.             TechnologyId: TechnologyId,  
  15.             Description: Description,  
  16.             Contents: Content,  
  17.         }  
  18.   
  19.         $.ajax({  
  20.             url: 'Contribute/Contribute',  
  21.             type: 'POST',  
  22.             data: JSON.stringify(ContributeModel),  
  23.             contentType: 'application/json;charset=utf-8',  
  24.             success: function (data) {  
  25.                 if (data.success == true) {  
  26.                     window.location.href = "../Account/Home";  
  27.                 }  
  28.                 else if (data.success == false) {  
  29.                     alert("Error occured..!!")  
  30.                 }  
  31.             },  
  32.             error: function () {  
  33.                 alert("Error occured..!!");  
  34.             },  
  35.         });  
  36.     }  
  37. });   
Step 6

Create an action method in contribute controller, which will insert the data into a databse, if the data is inserted successfully, it will return JSON result as true, else it returns false. In this action method from GetLoggedInUserId() method, we get the current user id who is logged into an Application.
  1. [HttpPost]  
  2.        public ActionResult Contribute(ContributeViewModel ContributeViewModel)  
  3.        {  
  4.            try  
  5.            {  
  6.                var technologyId = UnitoffWork.TechnologyRepository.GetSingle(x => x.Technology1 == ContributeViewModel.TechnologyId).Id;  
  7.                int userId = Helper.UserHelper.GetLoggedInUserId();  
  8.                UserPost userPost = new UserPost();  
  9.                userPost.UserId = userId;  
  10.                userPost.TechnologyId = technologyId;  
  11.                userPost.Title = ContributeViewModel.Title;  
  12.                userPost.Description = ContributeViewModel.Description;  
  13.                userPost.Contents = ContributeViewModel.Contents;  
  14.                userPost.CreationDate = DateTime.UtcNow;  
  15.                UnitoffWork.UserPostRepository.Insert(userPost);  
  16.                UnitoffWork.Save();  
  17.                return Json(new { success = true }, JsonRequestBehavior.AllowGet);  
  18.            }  
  19.            catch  
  20.            {  
  21.                return Json(new { success = false }, JsonRequestBehavior.AllowGet);  
  22.            }  
  23.        }   
Step 7

Create a View Model named as ArticleViewModel, as given below.
  1. public class ArticleViewModel  
  2.    {  
  3.        public ArticleViewModel(UserPost userPost, IEnumerable<PostLike> postLikes, List<UserComment> userComment)  
  4.        {  
  5.            Image = userPost.User.UserDetails.Count == 0 ? string.Empty : userPost.User.UserDetails.FirstOrDefault().Image == null ? string.Empty : userPost.User.UserDetails.FirstOrDefault().Image;  
  6.            FirstName = userPost.User.FirstName;  
  7.            LastName = userPost.User.LastName;  
  8.            Title = userPost.Title;  
  9.            Description = userPost.Description;  
  10.            PostId = userPost.Id;  
  11.            UserId = userPost.UserId;  
  12.            CreationDate = userPost.CreationDate.Value;  
  13.            Contents = userPost.Contents;  
  14.            Technology = userPost.Technology.Technology1;  
  15.        }  
  16.   
  17.        public string Image { getset; }  
  18.        public long PostId { getset; }  
  19.        public long UserId { getset; }  
  20.        public string Title { getset; }  
  21.        public string Description { getset; }  
  22.        public string Contents { getset; }  
  23.        public string Technology { getset; }  
  24.        public string FirstName { getset; }  
  25.        public string LastName { getset; }  
  26.        public DateTime CreationDate { getset; }  
  27.    } 
  28.  
In an Index method of controller, I am going to show a list of all the articles with Title, Description, Author Nam and Date etc. If we click on any record (the user would like to read any article from this list), then it will redirect to another action, which will show an article in the detail. For this, I have created an action method, as shown below. 
  1. public ActionResult Article(long Id)    
  2.         {    
  3.             int userId = Helper.UserHelper.GetLoggedInUserId();    
  4.             Expression<Func<UserPost, object>> parames1 = v => v.User;    
  5.             Expression<Func<UserPost, object>> parames2 = v => v.User.UserDetails;    
  6.             Expression<Func<UserPost, object>> parames3 = v => v.PostLikes;    
  7.             Expression<Func<UserPost, object>> parames4 = v => v.UserComments;    
  8.             Expression<Func<UserPost, object>>[] paramesArray = new Expression<Func<UserPost, object>>[] { parames1, parames2, parames3, parames4 };    
  9.             var userPost = UnitoffWork.UserPostRepository.GetAllSingleTracking(x => x.Id == Id, navigationProperties: paramesArray).Select(u => new ArticleViewModel(u, u.PostLikes.Where(x => x.UserId == userId && x.PostId == Id), u.UserComments.ToList()));    
  10.             ViewBag.Techonology = userPost.FirstOrDefault().Technology;    
  11.             return View(userPost);    
  12.         }  
Note

Here, I have used two more tables PostLikes & UserComments, which are used to get the count of likes & comment details. In the above action method, I used LINQ expression, using parameter array to get the record from the database on the basis of PostId.
 
Step 8

Now, create a View to show an article details for the above action, as given.
  1. @model IEnumerable<CoderFunda.ViewModel.Contribute.ArticleViewModel>  
  2. <div class="row pageEffect" id="pageEffect">  
  3.     <!---left content------->  
  4.     <form id="frmArticle">  
  5.         <div class="col-sm-8">  
  6.             <div class="col-sm-12"><span class="pageText1">Article </span><span class="pageText2">Detail</span></div>  
  7.             @if (Model.Count() > 0)  
  8.             {  
  9.                 foreach (var item in Model)  
  10.                 {  
  11.                     <div class="col-sm-12">  
  12.                         <div class="clearfix"></div>  
  13.                         <div class="articleOver">  
  14.                             <img src="~/Content/images/src.png" alt="" class="img-responsive">  
  15.                         </div>  
  16.                         <div class="article">  
  17.                             <h4 class="purpleText"><i>@item.Title</i></h4>  
  18.                             <span class="orangeText">  
  19.                                 By @item.FirstName @item.LastName  
  20.                                 <i class="fa fa-clock-o"></i> @item.CreationDate.ToShortDateString()  
  21.                                 @if (!string.IsNullOrEmpty(@item.UserSkill))  
  22.                                 {  
  23.                                     @item.UserSkill  
  24.                                 }  
  25.                                 <br />  
  26.                                 Technology : @ViewBag.Techonology  
  27.                             </span><br>  
  28.                             <b>@item.Description</b>  
  29.                         </div>  
  30.                         <div class="clearfix"></div>  
  31.                         <br>  
  32.                         <input type="hidden" id="hdnArticleContent" value="@item.Contents" />  
  33.                         <div id="dvshowArticleContent">  
  34.                         </div>  
  35.                         @if (CoderFunda.Helper.UserHelper.IsLogedIn())  
  36.                         {  
  37.                             <a href="javascript:void(0);" style="text-decoration: none !important;">  
  38.                                 @if (@item.IscurrentUserLiked)  
  39.                                 {  
  40.                                     <i class="fa fa-thumbs-up likeIcon" style="font-size:20px" data-toggle="tooltip" data-placement="top" title="Dislike" id="imgLike-1" onclick="RemoveLikes(@item.PostId,this);" data-original-title="DisLike">@item.LikeCount</i>  
  41.                                     <i class="fa fa-comment likeIconNew" style="font-size:20px;color:#4800ff"> @item.CommentCount</i>  
  42.                                 }  
  43.                                 else  
  44.                                 {  
  45.                                     <i class="fa fa-thumbs-up likeIconNew" style="font-size:20px" data-toggle="tooltip" data-placement="top" title="Like" id="imgLike-1" onclick="AddLikes(@item.PostId,this);" data-original-title="Like">@item.LikeCount</i>  
  46.                                     <i class="fa fa-comment likeIconNew" style="font-size:20px;color:#4800ff"> @item.CommentCount</i>  
  47.                                 }  
  48.   
  49.                             </a>  
  50.                             <div class="clearfix"></div>  
  51.                         }  
  52.                         else  
  53.                         {  
  54.                             <i class="fa fa-thumbs-up likeIcon" style="font-size:20px" data-toggle="tooltip" data-placement="top" title="Dislike" data-original-title="DisLike">@item.LikeCount</i>  
  55.                         }  
  56.                         <hr />  
  57.                         <div class="col-sm-12">  
  58.                             <div class="commentPic col-sm-4">  
  59.                                 @if (string.IsNullOrEmpty(item.Image))  
  60.                                 {  
  61.   
  62.                                     <img src="@Url.Content("~/Content/images/profile.jpg")" class="img-responsive" alt="" />  
  63.   
  64.                                 }  
  65.                                 else  
  66.                                 {  
  67.   
  68.                                     <img src="@Url.Content("~/Content/images/" + @item.Image)" class=" img-responsive" alt="" />  
  69.                                 }  
  70.                             </div>  
  71.                             <div class="row">  
  72.                                 <div class="col-xs-8 col-sm-10" style="text-align:left"><textarea class="form-control" id="taComment" placeholder="Comment here">  
  73.                                 @if (CoderFunda.Helper.UserHelper.IsLogedIn())  
  74.                                 {  
  75.                                     <div class="col-xs-4 commentBtn col-sm-4"><a href="javascript:void(0)" class="btn btn-primary post btnCommentSubmit" id="btnCommentSubmit" data-post-id="@item.PostId">Post</a></div>  
  76.                                 }  
  77.                                 else  
  78.                                 {  
  79.                                     <div class="col-xs-4 commentBtn col-sm-4"><a href="javascript:void(0)" class="btn btn-primary post" disabled="disabled">Post</a></div>  
  80.                                 }  
  81.                               
  82.                           
  83.                         <div class="clearfix"></div>  
  84.                         <hr>  
  85.                         <div class="col-sm-12">  
  86.                             @if (item.Comment != null)  
  87.                             {  
  88.                                 foreach (var comment in item.Comment)  
  89.                                 {  
  90.                                     <div class="col-sm-4">  
  91.                                         @if (string.IsNullOrEmpty(comment.Image))  
  92.                                         {  
  93.                                             <img src="@Url.Content(" ~="" content="" images="" profile.jpg")"="" class="img-responsive" alt="" style="height:30px; width:30px !important">  
  94.                                         }  
  95.                                         else  
  96.                                         {  
  97.                                             <img src="@Url.Content(" ~="" content="" images="" "="" +="" @comment.image)"="" class=" img-responsive" alt="" style="height:30px; width:30px !important">  
  98.                                         }  
  99.                                     </div>  
  100.                                     <div class="comment col-sm-8">  
  101.                                         @comment.Comment  
  102.                                         <br>  
  103.                                         <small class="pull-right authorText">By @comment.UserName</small>  
  104.                                     </div>  
  105.                                     <div class="clearfix"></div>  
  106.                                     <hr>  
  107.                                 }  
  108.                             }  
  109.                         </div>  
  110.                       
  111.                 }  
  112.             }  
  113.             <div class="clearfix"></div>  
  114.           
  115.       
  116.     <div class="clearfix"></div>  
  117.   
  118. <!------right content-----------> 
Step 9

Now, run the Application.
 
Access Contribute action method from the URL & you will see the view given below in which the user can enter the details, as given below.
 

 
Click Submit button. Now, open Index method on which you will get the article list, as given below.

 
If a user would like to read any article from this list, click on any article and the result is given below

 
Summary

In this article, you learned the basics of how to implement CKEditor in ASP.NET MVC.

Up Next
    Ebook Download
    View all
    Learn
    View all