Comment Or Reply To A Post In SharePoint Using Angular

Introduction

Nowadays commenting or replying to a post is the most common thing in all social networks. Hence, in this article, I am going to explain how it works in SharePoint using AngularJS. With the help of this article, you will learn how to set comment or reply feature to a post in SharePoint using AngularJS. 

Objective

Comments allow your website's visitors to have a discussion with you and each other. So, the main objective of this article is you to know how to set a comment feature to a post while developing your website or a page in SharePoint using AngularJS.

Overview
  • Create a picture library or a list in SharePoint to retrieve the posts to the web page
  • Create a web page with nice UI for displaying the posts and users to comment on the posts
  • Create appropriate HTML and AngularJS script for the web page
  • Create a list for storing the comments or replies for the posts
Step1
  • Create a list to store the posts. Where I am naming “Discussions” to the list and creating appropriate columns, as shown below.
    Angular

  • Create one more list to store all the replies or comments for the post, as shown below.

Step2
  • Write a script code to retrieve the discussions from the above list
  • Display all discussions in a webpage, where user can reply or comment for the post as shown below,

    Angular

    Where user can reply to every discussion individually by clicking on “Reply”. Also, they can read the all replies by clicking the “replies”

    Let’s have a look at “Reply” and “replies” as below:
  • When we click “Reply”, it shows as the below,

    Angular

  • By the click on submit, you can post your reply to the post.
  • When clicking on “replies”, it shows all respected replies as below

    Angular

  • When click on “Create new discussion”, it shows as following,

    Angular

  • You can add new discussion to the above page by using the above form
HTML code for the above UI

  1. <div class="container-fluid" ng-app="DiscussionApp" ng-controller="DiscussionController">  
  2.    <div class="form-horizontal col-lg-12 col-md-12 col-sm-12 col-xs-12">  
  3.       <button type="button" ng-click="CreateDisc();" style="float:right" class="btn btn-primary">Create New Discussion</button>  
  4.       <br/>  
  5.       <br/>  
  6.       <br/>  
  7.       <div class="form-group" id="HideWhenNew">  
  8.          <br/>  
  9.          <br/>  
  10.          <br/>  
  11.          <div class="col-lg-12 col-md-12 col-sm-12 col-xs-12">  
  12.             <div class="comment-maincol mb5" ng-repeat="Item in myarr">  
  13.                <div class="discussions-details ovrh pb5" id="replyDialogContainer">  
  14.                   <strong class="fltl col-xs-10"><a title="{{Item.Subject}}" href="javascript:(void)" class="tdn flight14 ct fbold color-liblack">{{Item.Subject}}</a></strong>  
  15.                   <p title="{{Item.Comments}}" class="pt5 pb5 flight13 fltl clrl" tabindex="0">{{Item.Comments}}</p>  
  16.                   <div class="replies-text cp fltr" tabindex="0"><span title="{{Item.ReplyCount}}" class="replies-count flight12">  
  17.                      {{Item.ReplyCount}}</span><span title="0" class="replies-count flight12" ng-if="Item.ReplyCount==null">  
  18.                      0</span><a class="replyarrow-up flight12" ng-click="ReadComment(Item.ID)" title="replies "> replies</a>  
  19.                   </div>  
  20.                   <div class="flight12 fltr clrl" id="childComment"><span title="{{Item.AuthorTitle}}" tabindex="0" class="fitalic">  
  21.                      {{Item.AuthorTitle}}</span> | <span title="{{Item.Created|date:'M/d/yyyy hh:mm:ss a'}}" tabindex="0" class="fitalic">   
  22.                      {{Item.Created|date:'M/d/yyyy hh:mm:ss a'}}</span> |  <span title="{{Item.CommentFor}}" tabindex="0" class="fitalic">For Doc:{{Item.CommentFor}}</span> <a title="" href="javascript:(void)" class="tdn curd" style="color: #008272;">  
  23.                      </a> | <a title="Reply" href="javascript:(void)" class="tdn" data-toggle="modal" data-target="#myModal" ng-click="replyComment(Item.ID)">  
  24.                      Reply</a>   
  25.                   </div>  
  26.                   <div id="showReplyBox{{Item.ID}}" style="display:none" class="showReplyBox">  
  27.                      <div class="col-xs-12 adddiscussion-popup replycomment-popup mt10 flight12"  style="display: block;">  
  28.                         <div class="adddiscussion-fields mt5 ml15 mr15" id="ReplyTxtArea">  
  29.                            <label title="Comments" tabindex="0">  
  30.                            Comments </label>  
  31.                            <textarea placeholder="Your comments here.." id="replyCommentContent" ng-model="db.Reply" rows="5" class="replyCommentContent"></textarea>  
  32.                            <span class="ErMsg">  
  33.                            This field is required</span>  
  34.                         </div>  
  35.                         <br/>  
  36.                         <div class="footer col-xs-12 mt20">  
  37.                            <div class="fltr mr5 mt10">  
  38.                               <button type="button" ng-click="SubmitToReplyList(DiscussionId,db);" class="btn btn-primary">Submit</button>  
  39.                               <button type="reset" ng-click="ForClose(Item.ID);" class="btn btn-warning">Close</button>  
  40.                            </div>  
  41.                         </div>  
  42.                      </div>  
  43.                   </div>  
  44.                   <div class="col-xs-12 col-lg-12 col-sm-12 col-md-12" ng-if="ActiveMe==Item.ID" id="RespReply{{Item.ID}}">  
  45.                      <div class="replycomment-area" style="display: block;" ng-repeat="Rply in myarrs">  
  46.                         <div class="comment-child-container" id="parent_48">  
  47.                            <div class="replycomment-inner mt10">  
  48.                               <p title="{{Rply.Reply}}" class="pt10 flight13 pb10 pl10 pr10" tabindex="0">  
  49.                                  {{Rply.Reply}}   
  50.                               </p>  
  51.                               <p class="flight12 fitalic pr10 pb10 ovrh"><span class="fltr block"><span title="{{Rply.ReplyAuthorTitle}}" tabindex="0">  
  52.                                  {{Rply.ReplyAuthorTitle}}</span> | <span title="{{Rply.ReplyCreated|date:'M/d/yyyy hh:mm:ss a'}}" tabindex="0">  
  53.                                  {{Rply.ReplyCreated|date:'M/d/yyyy hh:mm:ss a'}}</span> </span>  
  54.                               </p>  
  55.                            </div>  
  56.                         </div>  
  57.                      </div>  
  58.                   </div>  
  59.                </div>  
  60.             </div>  
  61.          </div>  
  62.       </div>  
  63.       <div id="ShowWhenNeedCreate">  
  64.          <div class="form-group">  
  65.             <label class="col-lg-3 col-md-3 col-sm-3 col-xs-3">CommentFor:</label>  
  66.             <div class="col-lg-9 col-md-9 col-sm-3 col-xs-9">  
  67.                <select class="form-control" ng-model="DataBind.CommentFor" >  
  68.                   <option value="">--select one--</option>  
  69.                   <option value="Doc1">Doc1</option>  
  70.                   <option value="Doc2">Doc2</option>  
  71.                   <option value="Doc3">Doc3</option>  
  72.                </select>  
  73.             </div>  
  74.          </div>  
  75.          <div class="form-group">  
  76.             <label class="col-lg-3 col-md-3 col-sm-3 col-xs-3">Subject:</label>  
  77.             <div class="col-lg-9 col-md-9 col-sm-3 col-xs-9">  
  78.                <input class="form-control" ng-model="DataBind.Subject" type="text" id="TxtSub"/>  
  79.                <span class="ErMsg" id="TxtSubMsg">Please fill out this!</span>  
  80.             </div>  
  81.          </div>  
  82.          <div class="form-group">  
  83.             <label class="col-lg-3 col-md-3 col-sm-3 col-xs-3">Comments:</label>  
  84.             <div class="col-lg-9 col-md-9 col-sm-3 col-xs-9">  
  85.                <textarea class="form-control" ng-model="DataBind.Comments" id="txtCommentFor"></textarea>  
  86.                <span class="ErMsg" id="CmntMsg">Please write some comments!</span>  
  87.             </div>  
  88.             <hr id="HrLine">  
  89.             </hr>  
  90.             <div class="form-group">  
  91.                <div class="col-lg-8 col-md-8 col-sm-8 col-xs-8"></div>  
  92.                <div class="col-lg-4 col-md-4 col-sm-4 col-xs-4"><button type="button" ng-click="SubmitToList(DataBind);" class="btn btn-primary BtnsAlign">Submit</button><button type="reset"  class="btn btn-warning BtnsAlign">Clear</button></div>  
  93.             </div>  
  94.          </div>  
  95.       </div>  
  96.    </div>  
  97. </div>  

The above HTML includes all functionalities like “Create new discussion”, “Reply”, “replies”, count for replies etc.

Script code for the above UI

  1. var myApp = angular.module('DiscussionApp', []); //,'ui.bootstrap'   
  2. var hash = [];  
  3. var hashs = [];  
  4. var ThisisforCommentFor = '';  
  5. myApp.controller('DiscussionController', ['$scope''$http''$q'function($scope, $http, $q, $compile) {  
  6.     $scope.showModal = false;  
  7.     $("#ShowWhenNeedCreate").hide();  
  8.     GetCustListProperties($scope, "Discussions");  
  9.     GetReplyListProperties($scope, "RepliesOfDiscussions");  
  10.   
  11.     GetDiscussionsItems($scope);  
  12.   
  13.     $scope.ReadComment = function(Thissd) {  
  14.         // alert(Thissd);  
  15.         $scope.ActiveMe = Thissd;  
  16.         $("#RespReply" + Thissd).toggle();  
  17.         GetReplies($scope, Thissd);  
  18.   
  19.     }  
  20.     $scope.replyComment = function(ThsId) {  
  21.         //$scope.showModal = true;  
  22.         //$("#myModal").show();  
  23.         $scope.DiscussionId = ThsId;  
  24.         $("#showReplyBox" + ThsId).toggle();  
  25.     }  
  26.     $scope.CreateDisc = function() {  
  27.         $("#ShowWhenNeedCreate").toggle('slow');  
  28.         //$("#HideWhenNew").hide();       
  29.     }  
  30.     $scope.ForClose = function(RespId) {  
  31.         $("#showReplyBox" + RespId).hide();  
  32.     }  
  33.     $scope.SubmitToReplyList = function(ToId, db) {  
  34.         if (JSON.stringify(db) === undefined) {  
  35.             $("#replyCommentContent").focus();  
  36.             $("span.ErMsg").show();  
  37.         } else {  
  38.             var Comments = JSON.stringify(db);  
  39.             Comments = Comments.replace(/[{}]/g, '');  
  40.             var datavalueOfModal = "{__metadata:{'type':'SP.Data.RepliesOfDiscussionsListItem'}," + Comments + ",DiscussionId:" + ToId + "}";  
  41.             //alert(datavalueOfModal);  
  42.             $.ajax({  
  43.                 url: _spPageContextInfo.webAbsoluteUrl + "/_api/web/lists/GetByTitle('RepliesOfDiscussions')/items",  
  44.                 type: "POST",  
  45.                 headers: {  
  46.                     "accept""application/json;odata=verbose",  
  47.                     "X-RequestDigest": $("#__REQUESTDIGEST").val(),  
  48.                     "content-Type""application/json;odata=verbose"  
  49.                 },  
  50.                 data: datavalueOfModal,  
  51.                 success: function(data) {  
  52.                     $scope.ReadComment(ToId);  
  53.                     GetReplyCountOfItem($scope, ToId);  
  54.   
  55.                 },  
  56.                 error: function(error) {  
  57.                     alert(JSON.stringify(error));  
  58.                 }  
  59.             });  
  60.         }  
  61.     }  
  62.     //  
  63.     $("#ReplyTxtArea textarea").keyup(function() {  
  64.         alert("textarea");  
  65.         if ($(this).val()) {  
  66.             $(this).css("border""1px solid #ababab");  
  67.             $("span.ErMsg").hide();  
  68.         }  
  69.     });  
  70.     //  
  71.     $scope.SubmitToList = function(FormValues) {  
  72.         if ($("#TxtSub").val() === "") {  
  73.   
  74.             $("#TxtSub").css("border""2px solid #FF0000");  
  75.             $("#TxtSub").focus();  
  76.             $("span#TxtSubMsg").show();  
  77.         } else if ($("#txtCommentFor").val() === "") {  
  78.             $("#txtMeetName").css("border""2px solid #FF0000");  
  79.             $("#txtCommentFor").focus();  
  80.             $("span#CmntMsg").show();  
  81.         } else {  
  82.             var data = JSON.stringify(FormValues);  
  83.             data = data.replace(/[{}]/g, '');  
  84.             var datavalue = "{__metadata:{'type':'SP.Data.DiscussionsListItem'}," + data + ",ParentId: " + $scope.MtParentId + "}";  
  85.             // console.log(datavalue);  
  86.             $.ajax({  
  87.                 url: _spPageContextInfo.webAbsoluteUrl + "/_api/web/lists/GetByTitle('Discussions')/items",  
  88.                 type: "POST",  
  89.                 headers: {  
  90.                     "accept""application/json;odata=verbose",  
  91.                     "X-RequestDigest": $("#__REQUESTDIGEST").val(),  
  92.                     "content-Type""application/json;odata=verbose"  
  93.                 },  
  94.                 data: datavalue,  
  95.                 success: function(data) {  
  96.                     $("#ShowWhenNeedCreate").hide();  
  97.                     $("#HideWhenNew").show();  
  98.                     GetDiscussionsItems($scope);  
  99.                     $scope.$apply(function() {  
  100.                         //$scope.Items=$scope.Items;  
  101.                         $scope.myarr = $scope.myarr;  
  102.                     })  
  103.                     console.log(data);  
  104.                 },  
  105.                 error: function(error) {  
  106.                     alert(JSON.stringify(error));  
  107.                 }  
  108.             });  
  109.         }  
  110.     }  
  111.     $("#ShowWhenNeedCreate textarea[id='txtCommentFor']").keyup(function() {  
  112.         if ($(this).val()) {  
  113.             $(this).css("border""1px solid #ababab");  
  114.             $("span#CmntMsg").hide();  
  115.         }  
  116.     });  
  117.     $("#ShowWhenNeedCreate input").keyup(function() {  
  118.         if ($(this).val()) {  
  119.             $(this).css("border""1px solid #ababab");  
  120.             $("span#TxtSubMsg").hide();  
  121.             // $("span#CmntMsg").hide();  
  122.         }  
  123.     });  
  124. }])  
  125.   
  126. function GetDiscussionsItems($scope) {  
  127.     hash = [];  
  128.     $.ajax({  
  129.         url: _spPageContextInfo.webAbsoluteUrl + "/_api/web/lists/GetByTitle('Discussions')/items?$filter=ParentId eq " + GetUrlKeyValue("itemid") + " &$select=*&$expand=Author&$select=Author/ID,Author/Title&$orderby=ID desc",  
  130.         method: "GET",  
  131.         async: false,  
  132.         headers: {  
  133.             "Accept""application/json;odata=verbose"  
  134.         },  
  135.         success: function(data) {  
  136.             $scope.Items = data.d.results;  
  137.             $scope.MtParentId = $scope.Items[0].ParentId;  
  138.             console.log($scope.MtParentId);  
  139.             $(data.d.results).each(function(listName, currentRowForBody) {  
  140.   
  141.                 var CommentFor = currentRowForBody.CommentFor;  
  142.                 var Subject = currentRowForBody.Subject;  
  143.                 var Comments = currentRowForBody.Comments;  
  144.                 var ReplyCount = currentRowForBody.ReplyCount;  
  145.                 var ParentId = currentRowForBody.ParentId;  
  146.   
  147.   
  148.                 var ID = currentRowForBody.ID;  
  149.                 var AuthorTitle = currentRowForBody.Author.Title;  
  150.                 var Created = currentRowForBody.Created;  
  151.                 //  console.log(currentRowForBody.Author.Title);  
  152.                 var Mu = Subject.split(",");  
  153.                 for (var i = 0; i < Mu.length; i++) {  
  154.                     var smss = {  
  155.                         Subject: Subject,  
  156.                         Comments: Comments,  
  157.                         ReplyCount: ReplyCount,  
  158.                         CommentFor: CommentFor,  
  159.                         ID: ID,  
  160.                         ParentId: ParentId,  
  161.                         AuthorTitle: AuthorTitle.split(",")[i],  
  162.                         Created: Created.split(",")[i]  
  163.                     }  
  164.                     hash.push(smss);  
  165.                 }  
  166.   
  167.   
  168.             });  
  169.             $scope.myarr = hash;  
  170.             //console.log($scope.myarr);  
  171.         },  
  172.         error: function(sender, args) {  
  173.             console.log(args.get_message());  
  174.         }  
  175.     });  
  176. }  
  177.   
  178. function GetReplyCountOfItem($scope, DscId) {  
  179.     $.ajax({  
  180.         url: _spPageContextInfo.webAbsoluteUrl + "/_api/web/lists/GetByTitle('Discussions')/items(" + DscId + ")",  
  181.         method: "GET",  
  182.         async: false,  
  183.         headers: {  
  184.             "Accept""application/json;odata=verbose"  
  185.         },  
  186.         success: function(data) {  
  187.             $scope.ReplyCounts = data.d.ReplyCount + 1;  
  188.             UpdateReplyCountInDiscList($scope, DscId, $scope.ReplyCounts);  
  189.             console.log($scope.ReplyCounts);  
  190.         },  
  191.         error: function(sender, args) {  
  192.             console.log(args.get_message());  
  193.         }  
  194.     });  
  195. }  
  196.   
  197. function UpdateReplyCountInDiscList($scope, DscId, NewRplyCount) {  
  198.     $.ajax({  
  199.         url: _spPageContextInfo.webAbsoluteUrl + "/_api/web/lists/GetByTitle('Discussions')/items(" + DscId + ")",  
  200.         type: "POST",  
  201.         headers: {  
  202.             "accept""application/json;odata=verbose",  
  203.   
  204.             "X-RequestDigest": $("#__REQUESTDIGEST").val(),  
  205.   
  206.             "content-Type""application/json;odata=verbose",  
  207.   
  208.             "IF-MATCH""*",  
  209.   
  210.             "X-HTTP-Method""MERGE"  
  211.         },  
  212.         data: "{__metadata:{'type':'SP.Data.DiscussionsListItem'},ReplyCount:" + NewRplyCount + "}",  
  213.         success: function(data) {  
  214.             GetDiscussionsItems($scope);  
  215.             $scope.$apply(function() {  
  216.                 $scope.myarr = $scope.myarr;  
  217.             })  
  218.         },  
  219.         error: function(error) {  
  220.             alert(JSON.stringify(error));  
  221.         }  
  222.     });  
  223. }  
  224.   
  225. function GetReplies($scope, ThisId) {  
  226.     $scope.myarrs = [];  
  227.     //hashs=[];  
  228.     hashs.length = 0;  
  229.     $.ajax({  
  230.         url: _spPageContextInfo.webAbsoluteUrl + "/_api/web/lists/GetByTitle('RepliesOfDiscussions')/items?$filter=DiscussionId eq " + ThisId + "&$select=*&$expand=Author&$select=Author/ID,Author/Title",  
  231.         method: "GET",  
  232.         async: false,  
  233.         headers: {  
  234.             "Accept""application/json;odata=verbose"  
  235.         },  
  236.         success: function(data) {  
  237.             $(data.d.results).each(function(listName, ReplyBody) {  
  238.                 var Reply = ReplyBody.Reply;  
  239.   
  240.                 var ReplyAuthorTitle = ReplyBody.Author.Title;  
  241.                 var ReplyCreated = ReplyBody.Created;  
  242.                 //  console.log(currentRowForBody.Author.Title);  
  243.                 var Mu = Reply.split(",");  
  244.                 for (var i = 0; i < Mu.length; i++) {  
  245.                     var smss = {  
  246.                         Reply: Reply.split(",")[i],  
  247.                         ReplyAuthorTitle: ReplyAuthorTitle.split(",")[i],  
  248.                         ReplyCreated: ReplyCreated.split(",")[i]  
  249.                     };  
  250.                     hashs.push(smss);  
  251.                 }  
  252.             });  
  253.             $scope.myarrs = hashs;  
  254.         },  
  255.         error: function(sender, args) {  
  256.             console.log(args.get_message());  
  257.         }  
  258.     });  
  259. }  

The above scripts includes all functionalities, validations etc.

References for the above files

Please add the following JS & CSS files to your code in the following order to make the application works.

    · CSS/jquery-ui.css

    · bootstrap.min.css

    · Discussion.css(custom CSS)

    · jquery.min.js

    · angular.min.js

    · Discussion.js(customized JS as defined above)

Conclusion

Hope, I did my job well. So, with the help of this article, you have learned how to set comment or reply feature to a post while developing your website or a page in SharePoint using AngularJS. Make sure to add the all needed reference files to work this application properly.

Thank you…Happy coding.


Similar Articles