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

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.

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.