{"id":2496,"date":"2016-07-18T14:48:49","date_gmt":"2016-07-18T12:48:49","guid":{"rendered":"https:\/\/sii.pl\/blog\/?p=2496"},"modified":"2023-08-18T11:39:28","modified_gmt":"2023-08-18T09:39:28","slug":"client-side-rendering-in-sharepoint","status":"publish","type":"post","link":"https:\/\/sii.pl\/blog\/en\/client-side-rendering-in-sharepoint\/","title":{"rendered":"Client Side Rendering in SharePoint"},"content":{"rendered":"\n<p>At this article I`d like to introduce Client Side Rendering (CSR) and how to use it on a real life example. Despite the fact that the CSR was introduced together with the SharePoint 2013 and have been making us happy with new UI possibilities for a few years already, it calls out questions. For example, developers are still using custom web parts to make customized list views. Instead of customizing standard SharePoint views with simple JavaScript.<br>Examples in topic are on typescript.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Introduction:<\/h2>\n\n\n\n<p>What is the CSR? It is the client side JavaScript based html render. CSR gets JSON object from the server and renders markup into the DOM object, using internal mechanisms.<br>Interesting thing is that the new feature of 2013th version \u201cScript Editor\u201d web part works the same way. I`ll describe interesting possibilities of \u201cScript Editor\u201d web part at the next topic.<br>How CSR customization looks like? It has two events and a structure of render methods:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>OnPreRender<\/li>\n\n\n\n<li>RenderView\n<ol class=\"wp-block-list\">\n<li>RenderHeader<\/li>\n\n\n\n<li>RenderBody\n<ol class=\"wp-block-list\">\n<li>RenderGroup<\/li>\n\n\n\n<li>RenderItem<\/li>\n\n\n\n<li>RenderField<\/li>\n<\/ol>\n<\/li>\n\n\n\n<li>RenderFooter<\/li>\n<\/ol>\n<\/li>\n\n\n\n<li>OnPostRender<\/li>\n<\/ol>\n\n\n\n<p>How you can see from the events named OnPreRender and OnPostRender, those events are raised before and after render respectively. They are usually used for style modifications when full definition of render is not needed. However, the interesting functional is in methods, which names are starting from Render word. There are re-definable functions to render SharePoint list views. The most important thing is that SharePoint standard definition is fully replaced with the custom definition of the method. For example if you redefine the RenderBody method you will not able to call SharePoint definition anymore, as well as child methods for Group, Item and Field. These child methods will return empty string. It means the higher level of customization \u2013 the more stuff you have to redefine.<br>To register your customization you have to call method:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\nSPClientTemplates.TemplateManager.RegisterTemplateOverrides(options);\n<\/pre><\/div>\n\n\n<p>This method accepts the object with the following structure:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\nvar options = {\nOnPreRender: &#x5B;(ctx) =&gt; { \/*prerender action*\/  }],\nTemplates: {\nHeader: (ctx) =&gt; { \/*Header HTML string*\/return &quot;&quot;; },\nBody: (ctx) =&gt; { \/*Body  HTML string*\/return &quot;&quot;; },\nView: (ctx) =&gt; { \/*View HTML string*\/return &quot;&quot;; },\nGroup: (ctx) =&gt; { \/*Group HTML string*\/return &quot;&quot;; },\nItem: (ctx) =&gt; { \/*Item HTML string*\/return &quot;&quot;; },\nFields: {\n&quot;fieldInternalName&quot;: {\n&quot;NewForm&quot;: (ctx) =&gt; { \/*new form view HTML string*\/return &quot;&quot;; },\n&quot;EditForm&quot;: (ctx) =&gt; { \/*edit form view HTML string*\/return &quot;&quot;; },\n&quot;DisplayForm&quot;: (ctx) =&gt; { \/*display form view HTML string*\/return &quot;&quot;; }\n}\n},\nFooter: (ctx) =&gt; { \/*Footer HTML string*\/return &quot;&quot;; }\n},\nOnPostRender: &#x5B;(ctx) =&gt; { \/*postrender action*\/ }]\n};\n<\/pre><\/div>\n\n\n<p>All object properties except On\u2026Render events are nullable, and if the value is not passed &#8211; then standard SharePoint method will be called.<br>Contrary to the common opinion that the JSLink is not equal to CSR, SharePoint have options to register custom render script: JSLink, \u201cScript Editor\u201d web part next to View are the safest ways. You can use master page script link, custom action etc. but in this case you need to be sure that the &#8220;clienttemplates.js&#8221; SOD is loaded.<br>Let`s look briefly to the JSLink syntax:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>To specify the URL to the script you should use the following tokens:\n<ol class=\"wp-block-list\">\n<li>~site \u2013 reference to the current SharePoint site (or \u201cWeb\u201d)<\/li>\n\n\n\n<li>~sitecollection \u2013 reference to the current SharePoint site collection (or \u201cSite\u201d)<\/li>\n\n\n\n<li>~layouts \u2013 version specific reference to the web application Layouts folder (so it will automatically swap out \/_layouts\/14 or \/_layouts\/15 for you)<\/li>\n\n\n\n<li>~sitecollectionlayouts \u2013 reference to the layouts folder in the current site collection (e.g. \/sites\/team\/_layouts\/15)<\/li>\n\n\n\n<li>~sitelayouts \u2013 reference to the layouts folder in the current site (e.g. \/sites\/teams\/subsite\/_layouts\/15)<\/li>\n<\/ol>\n<\/li>\n\n\n\n<li>If you need to specify few JavaScript links at the same time than use \u201c|\u201d separator<\/li>\n<\/ol>\n\n\n\n<p>We have a project, which is a small mail service with possibility to prepare the email content and send it to target audience. This solution contains two lists: \u201cNewsletter\u201d and \u201cNewsletter Contents\u201d.<br>Newsletter &#8211; defines the mail header and the list of recipients. On a main view there should be a possibility to preview email body.<br>Newsletter Contents \u2013 defines the list of containing contents with its own attachments and external references. There could be a few Contents for each \u201cNewsletter\u201d. Content should be created from Newsletter only.<br>The functionality with email preview and blocking the item creation was developed using the CSR. For those purposes we defined two fields:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: xml; title: ; notranslate\" title=\"\">\n&lt;Field ID=&quot;{4b5c1676-333a-4bd5-aefb-35e156765972}&quot;\nSourceID=&quot;&lt;%= sourceid %&gt;&quot;\nStaticName=&quot;MailexContentsStub&quot;\nShowInNewForm=&quot;FALSE&quot;\nShowInEditForm=&quot;FALSE&quot;\nName=&quot;MailexContentsStub&quot;\nJSLink=&quot;~sitecollection\/SiteAssets\/Mailex\/field.newsletter.content.js&quot;\nDisplayName=&quot;Content Preview&quot;\nRequired=&quot;FALSE&quot;\nEnforceUniqueValues=&quot;FALSE&quot;\nIndexed=&quot;FALSE&quot;\nMaxLength=&quot;255&quot;\nGroup=&quot;Blog Mail&quot;\nType=&quot;Text&quot;&gt;&lt;\/Field&gt;\n \n&lt;Field\nType=&quot;Lookup&quot;\nID=&quot;{225bfe7c-6043-4140-aa03-7dd2b17bba13}&quot;\nJSLink=&quot;~sitecollection\/SiteAssets\/Mailex\/field.newsletterlookup.js&quot;\nSourceID=&quot;&lt;%= sourceid %&gt;&quot;\nStaticName=&quot;MailexContToNewsLook&quot;\nName=&quot;MailexContToNewsLook&quot;\nDisplayName=&quot;Newsletter&quot;\nRequired=&quot;TRUE&quot;\nEnforceUniqueValues=&quot;FALSE&quot;\nList=&quot;&lt;%= listid %&gt;&quot; WebId=&quot;&lt;%= webid %&gt;&quot;\nShowField=&quot;Title&quot;\nUnlimitedLengthInDocumentLibrary=&quot;FALSE&quot;\nGroup=&quot;Blog Mail&quot; &gt;&lt;\/Field&gt;\n<\/pre><\/div>\n\n\n<p>As you can see JSLink points to ~sitecollection, this token is replaced with SPSite server relative URL by SharePoint automatically. Please take a look to SourceID, List, WebId attribute values: this syntax is used for auto fill values using the underscore.js template during the deployment time. Underscore.js is quite useful library. With specific tag, you can insert the normal text as well as executable code and html escaped text. More details by link http:\/\/underscorejs.org\/#template<br>Let\u2019s take a look to real life view:<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2016\/04\/newsletterlist.png\"><img decoding=\"async\" width=\"300\" height=\"151\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2016\/04\/newsletterlist-300x151.png\" alt=\"newsletter list view\" class=\"wp-image-3096\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2016\/04\/newsletterlist-300x151.png 300w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2016\/04\/newsletterlist.png 696w\" sizes=\"(max-width: 300px) 100vw, 300px\" \/><\/a><\/figure>\n\n\n\n<p>When you chose the single list item, custom ribbon action is activated. On click \u201cAdd Content\u201d button, the NewForm modal dialog for Newsletter Content will be opened. NewsletterId of the selected item will be passed to this dialog box via URL. The NewForm contains \u201cNewsletter\u201d field with CSR (you can find xml definition of the field earlier).<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2016\/04\/newsletterform_main.png\"><img decoding=\"async\" width=\"231\" height=\"300\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2016\/04\/newsletterform_main-231x300.png\" alt=\"Newsletter new item form\" class=\"wp-image-3099\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2016\/04\/newsletterform_main-231x300.png 231w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2016\/04\/newsletterform_main.png 661w\" sizes=\"(max-width: 231px) 100vw, 231px\" \/><\/a><\/figure>\n\n\n\n<p>After item creation we return to main view of Newsletter list, and click on Contents link, it is second CSR field. This is a stub field, which is hidden in all forms except display form. On click would be opened modal dialog with email preview:<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2016\/04\/newsletterpreview.png\"><img decoding=\"async\" width=\"278\" height=\"300\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2016\/04\/newsletterpreview-278x300.png\" alt=\"Newsletter preview\" class=\"wp-image-3097\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2016\/04\/newsletterpreview-278x300.png 278w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2016\/04\/newsletterpreview.png 784w\" sizes=\"(max-width: 278px) 100vw, 278px\" \/><\/a><\/figure>\n\n\n\n<p>In case if you would like to create new item for newsletter content via standard SharePoint New Item button you will see following error:<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2016\/04\/newsletterform.png\"><img decoding=\"async\" width=\"300\" height=\"245\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2016\/04\/newsletterform-300x245.png\" alt=\"Newsletter edit form\" class=\"wp-image-3098\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2016\/04\/newsletterform-300x245.png 300w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2016\/04\/newsletterform.png 710w\" sizes=\"(max-width: 300px) 100vw, 300px\" \/><\/a><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Implementation:<\/h2>\n\n\n\n<p>So, now I`ll describe how CSR script was created for the Newsletter lookup field. The content preview was made similar way, but was much more simple than this lookup.<br>How it was developed: I`ve created TS file field.newsletterlookup.ts, which contains all logic around this field modification and validation. Let\u2019s take a look part by part:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Template registration: <\/li>\n<\/ol>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\n$(document).ready(() =&gt; {\nSP.SOD.executeFunc(&quot;clienttemplates.js&quot;, &quot;SPClientTemplates&quot;, function () {\nSPClientTemplates.TemplateManager.RegisterTemplateOverrides({\nTemplates: {\nFields: {\n&#039;MailexContToNewsLook&#039;: {\n&#039;EditForm&#039;: NewsletterLookupFieldCsr.newsletterNewAndEdit,\n&#039;NewForm&#039;: NewsletterLookupFieldCsr.newsletterNewAndEdit\n}\n}\n}\n});\n});\n});\n<\/pre><\/div>\n\n\n<p>This template is simple and we can use the single render template for New and Edit forms. DisplayForm will show the normally rendered lookup field. The template building module has an interface:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\nexport function newsletterNewAndEdit(ctx) : string\n<\/pre><\/div>\n\n\n<p>The input parameter ctx is the current CSR context generated on server side. Context \u201cctx\u201d contains information regarding the list, item and rendering methods. Render function returns string value with field value wrapped in html markup. However, we need to do some more operations to make render mechanism working correctly. We need to register validators and define post back functions. So let\u2019s take a look closely:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\nconst formCtx = SPClientTemplates.Utility.GetFormContextForCurrentField(ctx);\nif (formCtx == null || formCtx.fieldSchema == null)\nreturn &quot;&quot;;\nconst validators = new SPClientForms.ClientValidation.ValidatorSet();\nvalidators.RegisterValidator(new NewsletterLookupFieldValidator());\nformCtx.registerClientValidator(formCtx.fieldName, validators);\nformCtx.registerValidationErrorCallback(formCtx.fieldName, newsletterLookupOnError);\nformCtx.registerGetValueCallback(formCtx.fieldName, () =&gt; {\nvar el = document.getElementById(readField);\nif (typeof el != &quot;undefined&quot; &amp;&amp; el != null) {\nconst lookUpVal =\n(&lt;HTMLInputElement&gt;document\n.getElementById(&quot;inpNewsletterHiddenValue &quot;)).value;\nif (!lookUpVal || lookUpVal === &quot;none&quot;) {\n} else {\nreturn lookUpVal;\n}\n}\nreturn null;\n<\/pre><\/div>\n\n\n<ol class=\"wp-block-list\" start=\"2\">\n<li>Custom validation. We will be using field validator to implement restrictions which won\u2019t allow user to create an item directly from the list:<\/li>\n<\/ol>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\nconst validators = new SPClientForms.ClientValidation.ValidatorSet();\nvalidators.RegisterValidator(new NewsletterLookupFieldValidator());\nformCtx.registerClientValidator(formCtx.fieldName, validators);\n<\/pre><\/div>\n\n\n<p>Method RegisterValidator accepts new instance if an object with Validate method. In our case this object is NewsletterLookupFieldValidator:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\nexport class NewsletterLookupFieldValidator {\npublic Validate() {\nlet isError = false;\nlet errorMessage = &quot;&quot;;\nconst el = document.getElementById(&quot;inpNewsletterHiddenValue&quot;);\nif (typeof el != &quot;undefined&quot; &amp;&amp; el != null) {\nconst lookUpVal = (&lt;HTMLInputElement&gt;el).value;\nif (!lookUpVal || lookUpVal === &quot;none&quot;) {\nisError = true;\nerrorMessage = &quot;Item cannot be created\/updated without related Newsletter.\nPlease create an item via Newsletter ribbon control&quot;;\n}\n} else {\nisError = true;\nerrorMessage = &quot;Html element not found&quot;;\n}\nreturn new SPClientForms.ClientValidation.ValidationResult(isError, errorMessage);\n}\n};\n<\/pre><\/div>\n\n\n<p>As you can see this method returns the ValidationResult object, which later will be passed into the Validation callback. Usually validation method checks the user actions on UI. In our case we will just check if the Newsletter ID is set.<\/p>\n\n\n\n<p>To register Validation Callback, the method which will be called on validation error, you need to call:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\nformCtx.registerValidationErrorCallback(formCtx.fieldName, newsletterLookupOnError);\n<\/pre><\/div>\n\n\n<p>Callback method definition is:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\nfunction newsletterLookupOnError (error) {\ndocument.getElementById(&quot;spnError&quot;).innerHTML = `&lt;span\nrole=&#039;alert&#039;&gt;${error.errorMessage}&lt;\/span&gt;`;\n}\n<\/pre><\/div>\n\n\n<p>This method returns html markup with an error text passed from Validation method to ValidationResult constructor.<\/p>\n\n\n\n<div style=\"height:20px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<p>The next step is to define Get Value callback. This method gathers value from your custom markup and returns it in SharePoint format. In our case it is lookup value in format \u201cid;#title\u201d.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\nformCtx.registerGetValueCallback(formCtx.fieldName, () =&gt; {\nvar el = document.getElementById(readField);\nif (typeof el != &quot;undefined&quot; &amp;&amp; el != null) {\nconst lookUpVal =\n(&lt;HTMLInputElement&gt;document\n.getElementById(&quot;inpNewsletterHiddenValue &quot;)).value;\nif (!lookUpVal || lookUpVal === &quot;none&quot;) {\n} else {\nreturn lookUpVal;\n}\n}\nreturn null;\n});\n<\/pre><\/div>\n\n\n<p>After definition of all post render actions, we will be rendering current value for EditForm and for set default value:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\nlet currentValue = &quot;none&quot;;\nlet curDisplayName = &quot;none&quot;;\nconst lookupValues = ctx.CurrentItem&#x5B;&quot;MailexContToNewsLook&quot;];\nif (lookupValues != null &amp;&amp; lookupValues.length &gt; 0) {\nconst arr = lookupValues.split(&quot;;#&quot;);\ncurDisplayName = arr&#x5B;1];\ncurrentValue = lookupValues;\n}\nconst html = `&lt;span&gt;&lt;span&gt;&lt;input type=&quot;hidden&quot; id=&quot;inpNewsletterHiddenValue&quot; value=&quot;${currentValue}&quot;\/&gt;&lt;\/span&gt;&lt;span class=&quot;ms-standardheader&quot; id=&quot;spanNewsletterValue&quot;&gt;${curDisplayName}&lt;\/span&gt;&lt;br\/&gt;&lt;div id=&quot;spnError&quot; class=&quot;ms-formvalidation ms-csrformvalidation&quot;&gt;&lt;\/div&gt;&lt;\/span&gt;`;\n<\/pre><\/div>\n\n\n<p>In case of a NewForm we have to check if there is Newsletter ID passed via URL from \u201cAdd Content\u201d custom ribbon action.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\nif (lookupValues == null || lookupValues.length === 0) {\nconst regex = new RegExp(`&#x5B;\\?&amp;]newsletterId=(&#x5B;^&amp;#]*)`);\nlet curId = regex.exec(location.search);\ncurId = (curId === null ? null : decodeURIComponent(curId&#x5B;1].replace(\/\\+\/g, &quot; &quot;)));\nif (curId != null &amp;&amp; curId.length !== 0) {\nretrieveNewData(&quot;inpNewsletterHiddenValue&quot;, , curId);\nvar clientContext = new SP.ClientContext();\nvar targetList = clientContext.get_web().get_lists().getByTitle(&quot;Newsletter&quot;);\nvar targetListItem = targetList.getItemById(curId);\nclientContext.load(targetListItem);\nclientContext.executeQueryAsync(() =&gt; {\n$(`#inpNewsletterHiddenValue`)\n.val(targetListItem.get_id()+&quot;;#&quot;+ targetListItem.get_item(&quot;Title&quot;));\n$(`#spanNewsletterValue`).text(targetListItem.get_item(&quot;Title&quot;));\n}, () =&gt; {\nconsole.log(&quot;Data retrieve failed&quot;);\n});\n}\n \n}\n<\/pre><\/div>\n\n\n<p>If the field doesn`t have any value, or \u201cnewsletterID\u201d have not been passed via url, then the \u201cnone\u201d text would be rendered. The value for hidden input inpNewsletterHiddenValue will be set \u201cnone\u201d as well. Now when you click Save button, a method Validation will raise an error with text: &#8220;Item cannot be created\/updated without related Newsletter. Please create an item via Newsletter ribbon control&#8221; and Validation will not be passed.<br>I`ve mentioned two customized fields at the beginning, but the second field is quite simple. There is no validators and \u201cget value\u201d postback. There is only Link markup generator, but under the hood, there are some actions to retrieve list items data and render it into html using underscore.js.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Conclusion:<\/h2>\n\n\n\n<p>To summarize the topic values I`d say CSR it is the very flexible and powerful tool and a kind of official Microsoft hack for SharePoint UI. Now you are able to:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Customize views without involving the SharePoint Designer.<\/li>\n\n\n\n<li>Create dependent fields<\/li>\n\n\n\n<li>Customize validation<\/li>\n\n\n\n<li>Change standard controls to something interesting like a progress bar or slider<\/li>\n<\/ol>\n\n\n\n<p>All these operations are compatible with SharePoint online and On-premise.<\/p>\n\n\n\n<p>In next topic I`ll describe some interesting features with Script Editor web part.<\/p>\n\n\n<div class=\"kk-star-ratings kksr-auto kksr-align-left kksr-valign-bottom\"\n    data-payload='{&quot;align&quot;:&quot;left&quot;,&quot;id&quot;:&quot;2496&quot;,&quot;slug&quot;:&quot;default&quot;,&quot;valign&quot;:&quot;bottom&quot;,&quot;ignore&quot;:&quot;&quot;,&quot;reference&quot;:&quot;auto&quot;,&quot;class&quot;:&quot;&quot;,&quot;count&quot;:&quot;3&quot;,&quot;legendonly&quot;:&quot;&quot;,&quot;readonly&quot;:&quot;&quot;,&quot;score&quot;:&quot;4.3&quot;,&quot;starsonly&quot;:&quot;&quot;,&quot;best&quot;:&quot;5&quot;,&quot;gap&quot;:&quot;11&quot;,&quot;greet&quot;:&quot;&quot;,&quot;legend&quot;:&quot;4.3\\\/5 ( votes: 3)&quot;,&quot;size&quot;:&quot;18&quot;,&quot;title&quot;:&quot;Client Side Rendering in SharePoint&quot;,&quot;width&quot;:&quot;119.2&quot;,&quot;_legend&quot;:&quot;{score}\\\/{best} ( {votes}: {count})&quot;,&quot;font_factor&quot;:&quot;1.25&quot;}'>\n            \n<div class=\"kksr-stars\">\n    \n<div class=\"kksr-stars-inactive\">\n            <div class=\"kksr-star\" data-star=\"1\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"2\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"3\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"4\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"5\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n    <\/div>\n    \n<div class=\"kksr-stars-active\" style=\"width: 119.2px;\">\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n    <\/div>\n<\/div>\n                \n\n<div class=\"kksr-legend\" style=\"font-size: 14.4px;\">\n            4.3\/5 ( votes: 3)    <\/div>\n    <\/div>\n","protected":false},"excerpt":{"rendered":"<p>At this article I`d like to introduce Client Side Rendering (CSR) and how to use it on a real life &hellip; <a class=\"continued-btn\" href=\"https:\/\/sii.pl\/blog\/en\/client-side-rendering-in-sharepoint\/\">Continued<\/a><\/p>\n","protected":false},"author":81,"featured_media":537,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_editorskit_title_hidden":false,"_editorskit_reading_time":0,"_editorskit_is_block_options_detached":false,"_editorskit_block_options_position":"{}","inline_featured_image":false,"footnotes":""},"categories":[1320],"tags":[1345,1476,1338,1411,1413,1474,1475],"class_list":["post-2496","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-hard-development","tag-sharepoint-en","tag-csr-en","tag-javascript-en","tag-sharepoint-2013-en","tag-sharepoint-2016-en","tag-typescript-en","tag-underscore-js-en"],"acf":[],"aioseo_notices":[],"republish_history":[],"featured_media_url":"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2015\/10\/16_SharePoint_v2.jpg","category_names":["Hard development"],"_links":{"self":[{"href":"https:\/\/sii.pl\/blog\/en\/wp-json\/wp\/v2\/posts\/2496"}],"collection":[{"href":"https:\/\/sii.pl\/blog\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/sii.pl\/blog\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/sii.pl\/blog\/en\/wp-json\/wp\/v2\/users\/81"}],"replies":[{"embeddable":true,"href":"https:\/\/sii.pl\/blog\/en\/wp-json\/wp\/v2\/comments?post=2496"}],"version-history":[{"count":2,"href":"https:\/\/sii.pl\/blog\/en\/wp-json\/wp\/v2\/posts\/2496\/revisions"}],"predecessor-version":[{"id":23588,"href":"https:\/\/sii.pl\/blog\/en\/wp-json\/wp\/v2\/posts\/2496\/revisions\/23588"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/sii.pl\/blog\/en\/wp-json\/wp\/v2\/media\/537"}],"wp:attachment":[{"href":"https:\/\/sii.pl\/blog\/en\/wp-json\/wp\/v2\/media?parent=2496"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/sii.pl\/blog\/en\/wp-json\/wp\/v2\/categories?post=2496"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/sii.pl\/blog\/en\/wp-json\/wp\/v2\/tags?post=2496"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}