<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Handlebars Archives - Michael Soriano</title>
	<atom:link href="https://michaelsoriano.com/tag/handlebars/feed/" rel="self" type="application/rss+xml" />
	<link>https://michaelsoriano.com/tag/handlebars/</link>
	<description>I turn code into captivating user experiences for the web</description>
	<lastBuildDate>Wed, 14 Feb 2024 18:36:26 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.7.4</generator>
	<item>
		<title>Build a SharePoint Single-Page App using nothing but Front-End Code</title>
		<link>https://michaelsoriano.com/build-sharepoint-single-page-app-front-end-code/</link>
					<comments>https://michaelsoriano.com/build-sharepoint-single-page-app-front-end-code/#comments</comments>
		
		<dc:creator><![CDATA[Michael Soriano]]></dc:creator>
		<pubDate>Wed, 15 Jun 2016 15:49:28 +0000</pubDate>
				<category><![CDATA[CSS]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[SharePoint]]></category>
		<category><![CDATA[Handlebars]]></category>
		<category><![CDATA[REST]]></category>
		<guid isPermaLink="false">http://michaelsoriano.com/?p=5501</guid>

					<description><![CDATA[<p>For this session, I would like to show you how to build a &#8220;mini&#8221; single page application in SharePoint 2013. A single page application that is ALL Front-end code (JavaScript, HTML and CSS); while using SP&#8217;s REST services. We&#8217;re also using Bootstrap for the responsiveness and tab interface, Handlebars for the templating, as well as [&#8230;]</p>
<p>The post <a href="https://michaelsoriano.com/build-sharepoint-single-page-app-front-end-code/">Build a SharePoint Single-Page App using nothing but Front-End Code</a> appeared first on <a href="https://michaelsoriano.com">Michael Soriano</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>For this session, I would like to show you how to build a &#8220;mini&#8221; single page application in SharePoint 2013. A single page application that is ALL Front-end code (JavaScript, HTML and CSS); while using SP&#8217;s <a href="https://msdn.microsoft.com/en-us/library/office/fp142380.aspx">REST services</a>. We&#8217;re also using <a href="http://getbootstrap.com/">Bootstrap</a> for the responsiveness and tab interface, <a href="http://handlebarsjs.com/">Handlebars</a> for the templating, as well as <a href="https://jquery.com/">jQuery</a> for everything else.</p>



<h5 class="wp-block-heading"><a id="user-content-note-that-this-will-require-the-following-files" class="anchor" href="https://github.com/michaelsoriano/sp-tabbed-containers#note-that-this-will-require-the-following-files" aria-hidden="true"></a>Note that this will require the following files:</h5>



<ul class="wp-block-list">
<li>jquery.min.js</li>



<li>bootstrap.min.js</li>



<li>handlebars.min.js</li>



<li>moment.min.js</li>



<li>editor.js</li>



<li>editor.css</li>



<li>bootstrap.min.css</li>



<li>font-awesome.min.css</li>
</ul>



<h5 class="wp-block-heading">The plugin already includes the above files via CDN.</h5>



<p class="btn"><a href="https://github.com/michaelsoriano/sp-tabbed-containers">View in Github</a></p>



<p>We are building &#8220;<em>Tab Containers</em>&#8220;. Basically, content that is shown in different tabs in a page. The entire CRUD interface also comes with it &#8211; so we&#8217;ll be able to add, edit and delete tab content and items, all in one page (without refreshing).</p>



<h3 class="wp-block-heading">Why is this Useful?</h3>



<p>Well there really is no way to achieve this in SharePoint. If you want to add Tabs inside an SP page, you would have to paste the whole code inside their editor. But updating this is quite cumbersome to most users.</p>



<p>This solution provides you with a nice interface to manage your tab content, while the data is stored in an SP list. The good thing about this is, you can use multiple apps and utilize just one list. So if you convert this into a webpart or an app &#8211; you simply need one list per site to make it work.</p>



<p>Ready to get started? Also, I&#8217;m only going to discuss the meat of the logic. You will need some basic JavaScript and SharePoint to follow and complete this tutorial.</p>



<h3 class="wp-block-heading">Create the List</h3>



<p>The data for our application will be stored in a custom list. The list will basically contain four columns: 1) <strong>Title</strong>: which is the default title field, 2) <strong>content</strong> which is a Rich Text type 3) <strong>tab-order</strong> a single line text value 4) <strong>webpart-id</strong> &#8211; this will be the identifier for our webpart (in case you want multiple webparts in the site).</p>



<p><img fetchpriority="high" decoding="async" width="509" height="474" class="alignnone size-full wp-image-5634" src="https://michaelsoriano.com/wp-content/uploads/2016/04/sp-tabs7.jpg" alt="sp-tabs7" srcset="https://michaelsoriano.com/wp-content/uploads/2016/04/sp-tabs7.jpg 509w, https://michaelsoriano.com/wp-content/uploads/2016/04/sp-tabs7-300x279.jpg 300w" sizes="(max-width: 509px) 100vw, 509px" /></p>



<p>The title column will hold tab title, content is the contents of the tab, tab order is for ordering the tabs from left to right. You can go ahead and fill it out with dummy data for now, so we can go ahead and fetch the data for our front end. Note that that I have the list template also included in the Github page.</p>



<h3 class="wp-block-heading">Fetch the Items</h3>



<p>We are going to use a slight variation of the &#8220;<a href="https://toddmotto.com/mastering-the-module-pattern/">Revealing Module</a>&#8221; pattern to construct our code. This is especially useful when you are expecting your code to be reused multiple times in a page. In our case, users might want multiple of these web parts in a page, so a &#8220;modularized&#8221; approach is needed.</p>



<pre class="wp-block-code"><code lang="javascript" class="language-javascript">var SpTabs = function(){
   //ENTER REST OF CODE HERE
return {
    init : init,
    getContent : getContent
  }
}</code></pre>



<p>As you can see, we are returning two public functions from our &#8220;SpTabs&#8221; object. The &#8220;init()&#8221; method will make the object unique per instance, while the &#8220;getContent()&#8221; will fetch the items for our view. Let&#8217;s build our init() function right below:</p>



<pre class="wp-block-code"><code lang="javascript" class="language-javascript">var init = function(obj){
    setListName(obj.listName);
    setWebPartId(obj.webPartId);
    setListItemEntityTypeFullName();
    checkPermissions();
}</code></pre>



<p>Inside our &#8220;init()&#8221;, we have some setters. It simply sets our module up for execution. The setter functions are pretty self explanatory &#8211; and you can simply investigate what each of them does in the source code. Let&#8217;s continue getting our items:</p>



<pre class="wp-block-code"><code lang="javascript" class="language-javascript">var getContent = function(obj){
    var endpoint = "/_api/web/lists/getbytitle('"+listName+"')/Items?";
    endpoint = _spPageContextInfo.webAbsoluteUrl + endpoint + '$orderby=tab_x002d_order asc';
    endpoint += "&amp;$filter=(webpart_x002d_id eq '"+webPartId+"')";
    var ajax = $.ajax({
      url: endpoint,
      method: "GET",
      headers: { "Accept": "application/json; odata=verbose" },
      success : function(data){
        items = data.d.results;
        buildTabsHtml();
        buildTabsContentHtml();
      },
      error : function(data){
        console.log(data);
      }
    });
    return ajax;
  }
</code></pre>



<p>This is the AJAX call that goes into our API to fetch our items. As you can see, we are returning the variable &#8220;ajax&#8221; from the getContent() function, in cases where we want to add additional stuff once the response is received. But the default behavior is inside the &#8220;success&#8221; method of jQuery&#8217;s $.ajax(). </p>



<p>Note the two methods <strong>buildTabsHtml()</strong> and <strong>buildTabsContentHtml()</strong>, and our results are in our global var &#8220;items&#8221;. So we&#8217;re ready to build some output.</p>



<h3 class="wp-block-heading">Output with Handlebars</h3>



<p>Let&#8217;s create our <a href="http://handlebarsjs.com/">Handlebars</a> templates so we can use it to produce our content. In case you haven&#8217;t used it, Handlebars is a minimal template language for JavaScript. It just makes life easier. Note that we have to include our handlebars source to make it work. Also, we are using <a href="http://getbootstrap.com/">Bootstrap </a>for our tab styles. So you have to include that in your source as well.</p>



<p>The code that will make this work is inside our two methods <strong>buildTabsHtml()</strong> and <strong>buildTabsContentHtml()</strong>. Let&#8217;s go ahead and build that now:</p>



<pre class="wp-block-code"><code lang="javascript" class="language-javascript">function buildTabsHtml(){
    var source = $("#tabs-navigation-template").html();
    var template = Handlebars.compile(source);
    $(getId() + '.tabs-navigation').html(template(items));
    //atach handlers
    $(getId()+'.tabs-navigation li a').on('click',function(){
      $(getId()+'.tabs-navigation li').removeClass('active');
      $(this).closest('li').addClass('active');
      var id = $(this).attr('data-id');
      $(getId()+'.tab-item').addClass('hidden');
      $(getId()+'div.tab-item[data-id="'+id+'"]').removeClass('hidden');
      if(id === 'addNew'){
        addNewForm();
      }
    })
  }
</code></pre>



<p>The above will output the content of our tabs. It also attaches the handlers to the tab navigation elements. Next up is the <strong>buildTabsContentHtml()</strong> method:</p>



<pre class="wp-block-code"><code lang="javascript" class="language-javascript">function buildTabsContentHtml(){
    var source = $("#tabs-content-template").html();
    var template = Handlebars.compile(source);
    Handlebars.registerPartial("tabForm", $("#tabs-content-form-template").html());
    $(getId() + '.tabs-content').html(template(items));
    $.each(items,function(i,item){
      $(getId()+'[data-id="'+item.Id+'"] .editable-content').Editor(EditorOptions);
      $(getId()+'[data-id="'+item.Id+'"] .Editor-editor').html(item.content);
    })
    $(getId()+'.save-changes').on('click',function(){
      var id =$(this).closest('.tab-item').attr('data-id');
      if(validateFields(id)){
        $(this).addClass('fetching').html('<i class="fa fa-refresh fa-spin"></i> Saving...');
        $(getId()+'.editmode').css({'opacity':'.4'});
        setTimeout(function(){
          var ajax = submitChanges(id);
          ajax.done(function(data, xhr){
              var ajax2 = getContent();
              ajax2.done(function(){
                $(getId()+'.tabs-navigation li a[data-id="'+id+'"]').trigger('click');
                addButton();
              });
          });
        },1000);
      }else{
        showErrorMessage(id);
      }
      return false;
    })
</code></pre>



<p>Now things got a bit hairy. First you&#8217;ll notice our handlebars compile &#8211; which is normal, but note the &#8220;registerPartial()&#8221; method. This means that we&#8217;re adding another handlebars template into our existing template. This is the form that handles our inline editing. I&#8217;m not going to post the code on here, instead you can see the #tabs-content-form-template from our <a href="https://github.com/michaelsoriano/sp-tabbed-containers/blob/master/sp-tabbed-containers.txt">text</a> file &#8211; which simply contains a few input forms for our app.</p>



<h3 class="wp-block-heading">Why use partials within templates?</h3>



<p>This is another powerful feature of handlebars. This allows for more re-usability and &#8220;modularity&#8221; for your applications. In other words, we write once and re-use multiple times. In our case, the form can be reused multiple times across our application &#8211; in &#8220;edit&#8221; and &#8220;new&#8221; mode. This will become evident as you write along.</p>



<p>We&#8217;re also using a lightweight WYSWG editor called &#8220;<a href="http://suyati.github.io/line-control">Line Control</a>&#8220;. Since we&#8217;re already using Bootstrap and FontAwesome, it just makes sense that we use a plugin that requires the same libraries. So this is what&#8217;s happening on lines 8-9 above: &#8220;.Editor(EditorOptions)&#8221;, where &#8220;<em>EditorOptions</em>&#8221; is declared on top of of our file as an array.</p>



<h3 class="wp-block-heading">Insert, Update and Delete</h3>



<p>Finally, we attach our &#8220;Save&#8221; and &#8220;Delete&#8221; buttons to do a couple of REST calls to our server when clicked. First our &#8220;Save&#8221; button is connected to our &#8220;<em>submitChanges</em>(id)&#8221; method (which takes care of both &#8220;edits&#8221; and &#8220;inserts&#8221;), while the next call is to &#8220;<em>getContent</em>()&#8221; &#8211; which is our main function to grab the tab items.</p>



<p>The &#8220;Delete&#8221; will also consist of two main REST calls, which is to delete and fetch the records. Our &#8220;<em>deleteRecord</em>()&#8221; function is shown below:</p>



<pre class="wp-block-code"><code lang="javascript" class="language-javascript">function deleteRecord(tab){
    var ajax = $.ajax({
       url: tab.__metadata.uri,
       type: "POST",
       headers: {
           "Accept": "application/json;odata=verbose",
           "X-RequestDigest": $("#__REQUESTDIGEST").val(),
           "X-HTTP-Method": "DELETE",
           "If-Match": tab.__metadata.etag
       },
       success: function (data) {
          console.log('record has been deleted');
       },
       error: function (data) {
          console.log('there was a problem with deleting the record');
       }
   });
   return ajax;
  }</code></pre>



<p>While our &#8220;submitChanges()&#8221; method looks like so:</p>



<pre class="wp-block-code"><code lang="javascript" class="language-javascript">function submitChanges(id){
      var item = {
        "__metadata": { "type": ListItemEntityTypeFullName },
        "Title" :   $(getId()+'[data-id="'+id+'"] input[name="title"]').val(),
        "content" : $(getId()+'[data-id="'+id+'"] .Editor-editor').html(),
        "tab_x002d_order" : $(getId()+'[data-id="'+id+'"] input[name="tab-order"]').val()
      };
      if(id === 'addNew'){
        item.webpart_x002d_id = webPartId;
        var endpoint = "/_api/web/lists/getbytitle('" + listName + "')/items";
        ajax = $.ajax({
           url: _spPageContextInfo.webAbsoluteUrl + endpoint,
           type: "POST",
           contentType: "application/json;odata=verbose",
           data: JSON.stringify(item),
           headers: {
               "Accept": "application/json;odata=verbose",
               "X-RequestDigest": $("#__REQUESTDIGEST").val()
           },
           error: function (data) {
              console.log(data);
           }
       });
       return ajax;
      } //end addNew;
      var tabItem = findItem(id);
      ajax = $.ajax({
         url: tabItem.__metadata.uri,
         type: "POST",
         contentType: "application/json;odata=verbose",
         data: JSON.stringify(item),
         headers: {
             "Accept": "application/json;odata=verbose",
             "X-RequestDigest": $("#__REQUESTDIGEST").val(),
             "X-HTTP-Method": "MERGE",
             "If-Match": tabItem.__metadata.etag
         },
         error: function (data) {
            console.log(data);
         }
     });
     return ajax;
  }
</code></pre>



<p>Note that all of the REST calls all look similar, with a select few nodes that changes. First you&#8217;ll notice the &#8220;X-HTTP-Method&#8221; for edits is &#8220;MERGE&#8221; and &#8220;DELETE&#8221; for deleting. The rest are pretty much SharePoint REST API requirements &#8211; which you can find more on <a href="https://msdn.microsoft.com/en-us/library/office/jj860569.aspx">this page</a>. Our &#8220;item&#8221; object is also mapped to the names of the list columns that we have. Depending on your list &#8211; you may need to modify this area as well.</p>



<p>In our UI, note the placement of our buttons and our form:<br><img decoding="async" width="509" height="557" class="alignnone size-full wp-image-5632" src="https://michaelsoriano.com/wp-content/uploads/2016/04/sp-tabs5.jpg" alt="sp-tabs5" srcset="https://michaelsoriano.com/wp-content/uploads/2016/04/sp-tabs5.jpg 509w, https://michaelsoriano.com/wp-content/uploads/2016/04/sp-tabs5-274x300.jpg 274w" sizes="(max-width: 509px) 100vw, 509px" /><br>Lastly, you notice a couple of helper functions &#8220;getId()&#8221; and &#8220;findItem()&#8221;. The <strong>getId()</strong> simply returns our current div &#8211; with the &#8220;#&#8221; and a space as a string (or the CSS selector for the current div), while our <strong>findItem()</strong> loops through our global <strong>items</strong> object and returns the current item.</p>



<p>Moving forward, let&#8217;s look at a couple of important internal methods which includes our validation and error messaging mechanism.</p>



<h3 class="wp-block-heading">Form Validation</h3>



<p>Since we&#8217;re entering our data into our SharePoint lists through client side, we can implement a validation method using JavaScript as well. The cool thing about SP&#8217;s REST API has it&#8217;s own validation in the server side so all we have to worry about is the user experience.</p>



<pre class="wp-block-code"><code lang="javascript" class="language-javascript">function validateFields(id){
    errors = [];
    $('.error').remove();
    var title = $(getId()+'[data-id="'+id+'"] input[name="title"]');
    var content = $(getId()+'[data-id="'+id+'"] .Editor-editor');
    var tabOrder = $(getId()+'[data-id="'+id+'"] input[name="tab-order"]');
    if(title.val() == ''){
      var obj = {};
      obj.field = 'title';
      obj.message = 'Title cannot be empty'
      errors.push(obj);
    }
    if(content.html() == ''){
      var obj = {};
      obj.field = 'content';
      obj.message = 'Content cannot be empty'
      errors.push(obj);
    }
    if(tabOrder.val() == ''){
      var obj = {};
      obj.field = 'tab-order';
      obj.message = 'Tab order cannot be empty'
      errors.push(obj);
    }
    if(errors.length &gt; 0){
      return false;
    }
    return true;
  }
</code></pre>



<p>Our very simple validation code is above. Note that this happens every time that &#8220;submit&#8221; button is clicked. So it simply goes through the fields &#8211; check for empty and puts the errors in an array. I&#8217;m not checking for anything else like valid data etc &#8211; and feel free to add your own rules. Simply keep pushing the error messages into our array when invalid. Our messaging is handled in the code below:</p>



<pre class="wp-block-code"><code lang="javascript" class="language-javascript">function showErrorMessage(id){
    $.each(errors,function(i,er){
      var field = '';
      if(er.field === 'content'){
        field = $(getId()+'[data-id="'+id+'"] .Editor-container');
      }else{
        field = $(getId()+'[data-id="'+id+'"] input[name="'+er.field+'"]');
      }</code></pre>



<p><em>[the code above has been truncated due to an error w syntax highlighter&#8230; sorry]</em></p>



<p>The following screenshot shows our validation code in action. Error messaging is placed underneath each label and at the same time. This way, users can see where they had made an error and fix. Remember to add your own rules as necessary.</p>



<p><br><img decoding="async" width="516" height="502" class="alignnone size-full wp-image-5764" src="https://michaelsoriano.com/wp-content/uploads/2016/05/tabs-validation.png" alt="tabs-validation" srcset="https://michaelsoriano.com/wp-content/uploads/2016/05/tabs-validation.png 516w, https://michaelsoriano.com/wp-content/uploads/2016/05/tabs-validation-300x292.png 300w" sizes="(max-width: 516px) 100vw, 516px" /></p>



<h3 class="wp-block-heading">Checking Permissions</h3>



<p>Finally, since we&#8217;re not using the regular SharePoint process in updating a page with tabs, we need to come up with our own. See, the entity we&#8217;re updating is not the current page &#8211; but a list. So we need to check if the current user has permission to edit the list &#8211; and give them access to our newly created UI.<br>I found this <a href="http://www.lifeonplanetgroove.com/checking-user-permissions-from-the-sharepoint-2013-rest-api/">great article</a> on how to effectively do this &#8211; since Microsoft&#8217;s documentation is a bit vague. </p>



<p>We&#8217;re using the &#8220;effectiveBasePermissions&#8221; REST endpoint along with SP.BasePermissions() class &#8211; which we need from SP.ClientContext object. Yes, it&#8217;s a bit of a mess so simply check the code below:</p>



<pre class="wp-block-code"><code lang="javascript" class="language-javascript">function checkPermissions() {
    SP.SOD.executeFunc('sp.js', 'SP.ClientContext', function () {
      var call = jQuery.ajax({
          url: _spPageContextInfo.webAbsoluteUrl +
              "/_api/Web/lists/getbytitle('"+listName+"')/effectiveBasePermissions",
          type: "GET",
          dataType: "json",
          headers: {
              Accept: "application/json;odata=verbose"
          }
      });
      call.done(function (data, textStatus, jqXHR) {
          var permissions = new SP.BasePermissions();
          permissions.initPropertiesFromJson(data.d.EffectiveBasePermissions);
          var permLevels = [];
          for(var permLevelName in SP.PermissionKind.prototype) {
              if (SP.PermissionKind.hasOwnProperty(permLevelName)) {
                  var permLevel = SP.PermissionKind.parse(permLevelName);
                  if(permissions.has(permLevel)){
                        permLevels.push(permLevelName);
                  }
              }
          }
          // console.log(permLevels);
          if($.inArray('editListItems',permLevels) != -1){
            userCanEdit = true;
            addButton();
          }else{
            console.log('You dont have "editListItems" permissions on '+ listName);
          }
      });  //end done
    });
  }
</code></pre>



<p>We&#8217;re still using jQuery&#8217;s ajax to get information, though it&#8217;s wrapped inside a &#8220;SP.SOD.executeFunc()&#8221; method &#8211; which is Microsoft&#8217;s way of loading and executing internal scripts. What we get back is an array we&#8217;re calling &#8220;permLevels&#8221; This array contains all the permissions a user has against our list. </p>



<p>We&#8217;re simply looking for the &#8220;editListItems&#8221; &#8211; and if found, we&#8217;re show the button and let the user edit.<br><img decoding="async" width="638" height="495" class="alignnone size-full wp-image-5767" src="https://michaelsoriano.com/wp-content/uploads/2016/05/tabs-45.jpg" alt="tabs-45" srcset="https://michaelsoriano.com/wp-content/uploads/2016/05/tabs-45.jpg 638w, https://michaelsoriano.com/wp-content/uploads/2016/05/tabs-45-300x233.jpg 300w" sizes="(max-width: 638px) 100vw, 638px" /></p>



<h3 class="wp-block-heading">Final Steps</h3>



<p>Our code is now complete. Note that there is not a single line of .NET code above &#8211; it&#8217;s all JavaScript, HTML and CSS. All server interactions are done through the REST API. This code can be applied whichever way you want to implement &#8211; may it be a custom web part, an app part or simply add the code to a Content Editor.</p>



<p>Remember to update the initialize settings like below: The important part is the &#8220;webPartId&#8221; and &#8220;listName&#8221; parameters &#8211; which connects the plugin to the data you need.</p>



<p><img decoding="async" width="432" height="330" class="alignnone size-full wp-image-5631" src="https://michaelsoriano.com/wp-content/uploads/2016/04/sp-tabs4.jpg" alt="sp-tabs4" srcset="https://michaelsoriano.com/wp-content/uploads/2016/04/sp-tabs4.jpg 432w, https://michaelsoriano.com/wp-content/uploads/2016/04/sp-tabs4-300x229.jpg 300w" sizes="(max-width: 432px) 100vw, 432px" /></p>



<p>Once that&#8217;s done, simply reload the page and you should see your SPA in action. Note that the code editor I used is very basic &#8211; so you might need to go to the list itself when updating content.</p>



<p><img decoding="async" width="581" height="597" class="alignnone size-full wp-image-5858" style="border: 1px solid #ebebeb;" src="https://michaelsoriano.com/wp-content/uploads/2016/06/sp-tabs2.gif" alt="sp-tabs2"></p>



<p>This editor was mostly designed for quick updates to your content.</p>



<p>Remember, the purpose of this article was really to expose you to the inner workings of REST and how to build a single page application right inside SharePoint with existing open technologies such as jQuery, Handlebars and Bootstrap. </p>



<p>Hope you enjoy this piece. Let me know your comments below.</p>
<p>The post <a href="https://michaelsoriano.com/build-sharepoint-single-page-app-front-end-code/">Build a SharePoint Single-Page App using nothing but Front-End Code</a> appeared first on <a href="https://michaelsoriano.com">Michael Soriano</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://michaelsoriano.com/build-sharepoint-single-page-app-front-end-code/feed/</wfw:commentRss>
			<slash:comments>9</slash:comments>
		
		
			</item>
		<item>
		<title>Build a Better Photo Gallery for SharePoint using REST and Handlebars</title>
		<link>https://michaelsoriano.com/better-photo-gallery-sharepoint-rest-and-handlebars/</link>
					<comments>https://michaelsoriano.com/better-photo-gallery-sharepoint-rest-and-handlebars/#comments</comments>
		
		<dc:creator><![CDATA[Michael Soriano]]></dc:creator>
		<pubDate>Mon, 21 Mar 2016 01:01:35 +0000</pubDate>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[SharePoint]]></category>
		<category><![CDATA[Handlebars]]></category>
		<category><![CDATA[REST]]></category>
		<guid isPermaLink="false">http://michaelsoriano.com/?p=5473</guid>

					<description><![CDATA[<p>Working with SharePoint&#8217;s REST API is pretty cool. Lately, I&#8217;ve been writing plenty of applications where the entire CRUD is involved; all using SharePoint lists behind the scenes. Meaning, the entire front end is entirely up to me to build. This way, I can use different JavaScript libraries and frameworks when building these interfaces. Note [&#8230;]</p>
<p>The post <a href="https://michaelsoriano.com/better-photo-gallery-sharepoint-rest-and-handlebars/">Build a Better Photo Gallery for SharePoint using REST and Handlebars</a> appeared first on <a href="https://michaelsoriano.com">Michael Soriano</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>Working with SharePoint&#8217;s REST API is pretty cool. Lately, I&#8217;ve been writing plenty of applications where the entire <a href="https://en.wikipedia.org/wiki/Create,_read,_update_and_delete">CRUD</a> is involved; all using SharePoint lists behind the scenes. Meaning, the entire front end is entirely up to me to build. This way, I can use different JavaScript libraries and frameworks when building these interfaces.</p>



<h4 class="wp-block-heading">Note that this will require the following files:</h4>



<ul class="wp-block-list"><li>bootstrap.css</li><li>magnific-popup.css</li><li>jquery-1.12.0.min.js</li><li>jquery.magnific-popup.min.js</li></ul>



<p><strong>The plugin already includes the above files via CDN. The Plugin JavaScript and CSS is also included via RawGit &#8211; so changes may affect your working files.</strong></p>



<p class="btn"><a href="https://github.com/michaelsoriano/sp-photo-gallery">View in Github</a></p>



<p><br>Today, let&#8217;s look at something pretty simple. Let&#8217;s build a photo gallery using <a href="https://products.office.com/en-us/sharepoint/collaboration">SharePoint</a> Picture library as the backend, together with <a href="http://handlebarsjs.com/">Handlebars.js</a> &#8211; a good Javascript templating system. With this knowledge, you will gain good understanding on how to select items with SharePoint&#8217;s REST API, which I happen to have a <a href="https://michaelsoriano.com/understanding-sharepoint-rest-api-part-1-selecting-items/">post</a> on.</p>



<p><br><img decoding="async" width="750" height="500" class="alignnone size-full wp-image-5868" src="https://michaelsoriano.com/wp-content/uploads/2015/02/bspg2.jpg" alt="bspg2" srcset="https://michaelsoriano.com/wp-content/uploads/2015/02/bspg2.jpg 750w, https://michaelsoriano.com/wp-content/uploads/2015/02/bspg2-300x200.jpg 300w" sizes="(max-width: 750px) 100vw, 750px" /></p>



<p>Ready to get started? Roll up your sleeves and let&#8217;s write some code. Note that I will not go over the entire code base in this tutorial &#8211; just the meat of the logic.</p>



<h3 class="wp-block-heading">Setup the Gallery</h3>



<p>First we need to make sure we have a gallery to connect to. In SharePoint, you do this by going to &#8220;View All Site Content&#8221; and adding a new Picture Library. Note that for this demo I&#8217;m using SharePoint 2010 &#8211; I believe in newer versions you have to &#8220;<em>Add an App</em>&#8221; &gt; &#8220;<em>Photo Library</em>&#8220;.</p>



<p>Be sure to note the name of your library:<br><img decoding="async" width="660" height="469" class="alignnone size-full wp-image-5483" src="https://michaelsoriano.com/wp-content/uploads/2016/02/sp-photo-gallery-3.jpg" alt="sp-photo-gallery-3" srcset="https://michaelsoriano.com/wp-content/uploads/2016/02/sp-photo-gallery-3.jpg 660w, https://michaelsoriano.com/wp-content/uploads/2016/02/sp-photo-gallery-3-300x213.jpg 300w" sizes="(max-width: 660px) 100vw, 660px" /><br>Upload some images to your newly created library. Now we can continue and pull our images in the front end.</p>



<h3 class="wp-block-heading">The Javascript</h3>



<p>Create a Javasript file and name it sp-gallery.js. You can place it inside any SharePoint document library &#8211; and simply map to it using Windows Explorer so you can write to it just like you would as if it was a local file.</p>



<p>Let&#8217;s setup the wrapper for our gallery. We&#8217;re using the &#8220;<a href="https://addyosmani.com/resources/essentialjsdesignpatterns/book/#revealingmodulepatternjavascript">Revealing Module</a>&#8221; pattern so we can have methods that are public and private, as well as we keep our logic real tidy. We&#8217;re adding private variables inside our class so we can use it all over our code.</p>



<pre class="wp-block-code"><code lang="javascript" class="language-javascript">var gallery = function(list){
  var webUrl = _spPageContextInfo.webAbsoluteUrl;
  var listName = list;
  var limit = 20;
  var skip = 0;
  var total = 0;
}</code></pre>



<h6 class="wp-block-heading">Get the List Count</h6>



<p>Our first method is to grab the number of photos in our library. This is important so we can decide whether to show our &#8220;show more&#8221; button or not. Note the use our our &#8220;webUrl&#8221; and &#8220;listName&#8221; variables in our method. Add this code inside our gallery wrapper. This method is internal, so we create a function declaration:</p>



<pre class="wp-block-code"><code lang="javascript" class="language-javascript">function getListCount(webUrl,listName) {
    var url = webUrl + "/_vti_bin/listdata.svc/" + listName + '/$count';
    var ajax = $.ajax({
        url: url,
        method: "GET",
        headers: { "Accept": "application/json;odata=verbose,text/plain" },
        error: function (data) {
          console.log('error in fetching list count');
          console.log(data.responseJSON.error);
        }
    });
    return ajax;
}</code></pre>



<p>The above will return a &#8220;promise&#8221; object that we can use to manipulate later on. In the case above, it&#8217;s simply a number.</p>



<h3 class="wp-block-heading">Get the Gallery Items</h3>



<p>This method is the call to grab our list items. Again, we&#8217;re using jQuery&#8217;s &#8220;Ajax&#8221; method, returning a promise object.</p>



<pre class="wp-block-code"><code lang="javascript" class="language-javascript">function getListItems(webUrl,listName, itemId) {
    var url = webUrl + "/_vti_bin/listdata.svc/" + listName;
    if(itemId !== null){
      url += "(" + itemId + ")";
    }
    url += '?$top='+limit+'&amp;$skip='+skip;
    var ajax = $.ajax({
        url: url,
        method: "GET",
        headers: { "Accept": "application/json; odata=verbose" },
        error: function (data) {
          console.log(data.responseJSON.error);
        }
    });
    return ajax;
  }</code></pre>



<h3 class="wp-block-heading">Compile with HandleBars</h3>



<p>This method is taking the data that is returned from our ajax promise above, and compiling it with handlbars. We haven&#8217;t built our HTML yet &#8211; which contains the actual handebars template. Note that this is a public function, so we&#8217;re creating the function as a &#8220;function expression&#8221;:</p>



<pre class="wp-block-code"><code lang="javascript" class="language-javascript">var buildGallery = function(data){
      var source   = $("#photogallery").html();
      var template = Handlebars.compile(source);
      $('.photo-gallery-wrap').append(template(data));
      $('.popup').magnificPopup({
          type: 'image',
          gallery:{
            preload: [0,5],
            enabled:true
          },
          removalDelay: 300,
          mainClass: 'mfp-fade'
      });
  }</code></pre>



<p>Also note that I&#8217;ve added a &#8220;popup&#8221; functionality which we&#8217;ve instantiated in the code above. We&#8217;re using <a href="http://dimsemenov.com/plugins/magnific-popup/">magnificpopup.js</a> for this awesome feature.</p>



<h3 class="wp-block-heading">The &#8220;Show More&#8221; button</h3>



<p>We&#8217;re only loading a certain subset of photos in our gallery. We will have a button in the bottom of our images that when clicked, will do another fetch to our list and add them below. Again, this is public, so it&#8217;s a &#8220;function expression&#8221;.</p>



<pre class="wp-block-code"><code lang="javascript" class="language-javascript">var showmore = function (){
      $('#showmore').addClass('fetching').html('Loading images...');
      skip = skip+limit;
      var ajax2 = getListItems(webUrl,listName, null);
      ajax2.done(function(data){
        buildGallery(data);
        $('#showmore').removeClass('fetching').html('Show More');
        if($('.thumbnail-wrap').length &gt;= total){
            $('#showmore').hide();
        }
      });
      return false;
  }</code></pre>



<p>This sort of acts like an &#8220;infinite scroll&#8221; functionality &#8211; but with a button. I&#8217;m not particularly fond of that automatic loading.</p>



<h3 class="wp-block-heading">Initializing the Gallery</h3>



<p>Now that our methods are in place, it is time to tie them all together and returning them so we can call them outside of our class. We do this by creating an &#8220;init&#8221; function.</p>



<pre class="wp-block-code"><code lang="javascript" class="language-javascript">var gallery = function(list){
//our private vars here...
var init = function(){
      var ajax1 = getListCount(webUrl,listName);
      var ajax2 = getListItems(webUrl,listName, null);
      ajax1.done(function(data){
        total = data;
        if(total &lt;= limit){
          $('#showmore').hide();
        }
      });
      ajax2.done(function(data){
        buildGallery(data);
      });
  }
//the rest of the methods here...
//below returns our public methods for use:
 return {
    init : init,
    showmore : showmore,
    buildGallery : buildGallery
  }</code></pre>



<p>Notice that we are only returning the public functions above. So we are keeping our variables and private functions inaccessible from the outside world. Let&#8217;s move on to our helpers:</p>



<h3 class="wp-block-heading">HandleBar Helpers</h3>



<p>These methods doesn&#8217;t have to be our gallery code. This can live outside, so it can be accessed by Handlebars. The code is namespaced using the Handlebars object. I&#8217;ll explain what the do below:</p>



<pre class="wp-block-code"><code lang="javascript" class="language-javascript">Handlebars.registerHelper('findGroup', function(data) {
    var remove = _spPageContextInfo.webServerRelativeUrl;
    var str = data.Path;
    return str.replace(remove+'/','');
});
Handlebars.registerHelper('imgSrc', function(data) {
    var url = _spPageContextInfo.siteAbsoluteUrl;
    url += data.Path;
    url += '/' + data.Name
    return url;
});
Handlebars.registerHelper('imgSrcThumb', function(data) {
    var thumb = data.Name;
    thumb = thumb.replace('.jpg', '_jpg.jpg');
    var url = _spPageContextInfo.siteAbsoluteUrl;
    url += data.Path;
    url += '/_t/' + thumb;
    return url;
});</code></pre>



<p>We will use a &#8220;<em>findGroup</em>&#8221; helper inside our templates so we can &#8220;group&#8221; our photos together. This is what our &#8220;<em>Magnificpopup</em>&#8221; plugin requires &#8211; so when you click &#8220;next&#8221; or &#8220;previous&#8221; &#8211; it knows which photo to show.</p>



<p>The &#8220;imgSrc&#8221; helper simply returns the source of the images, while the &#8220;imgSrcThumb&#8221; returns the thumbnail path. Note that this helper only supports jpegs at the moment.</p>



<h3 class="wp-block-heading">The CSS</h3>



<p>We are simply displaying the thumbnails in a grid fashion, so our styles are quite basic. I&#8217;m using this inside a Bootstrap wrapper, so you can see the &#8220;.col&#8221; classes in our HTML later. Create a file and name it sp-gallery.css and add the code below:</p>



<pre class="wp-block-code"><code lang="css" class="language-css">.photo-gallery-wrap {
  overflow: hidden;
  margin-right: -30px;
}
.thumbnail {
  display: inline-block;
  width: 100%;
  height: 100px;
  background-position: center center !important;
  text-indent: -9999px;
}
.thumbnailHidden {
  display:none;
}
.showMoreWrap {
  clear:both;
  display:block;
}
#showmore {
  color:#fff;
}
#showmore.fetching {
  background:#AAD3AA;
  border:#9AC39A;
}
.thumbnail-wrap {
  margin-bottom: 25px;
}
.thumbnail-wrap.col-lg-3 {
  padding-left:0;
  padding-right: 30px;
}
@media(max-width:387px){
  .thumbnail-wrap.col-lg-3 {
    padding-right: 15px;
  }
  .col-xxs-6 {
    width:50%;
  }
  #showmore {
    display:block;
  }
}
@media(max-width:240px){
  .col-xxxs-12 {
    width:100%;
  }
}
/* overlay at start */
.mfp-fade.mfp-bg {
  opacity: 0;
  -webkit-transition: all 0.15s ease-out;
  -moz-transition: all 0.15s ease-out;
  transition: all 0.15s ease-out;
}
/* overlay animate in */
.mfp-fade.mfp-bg.mfp-ready {
  opacity: 0.8;
}
/* overlay animate out */
.mfp-fade.mfp-bg.mfp-removing {
  opacity: 0;
}
/* content at start */
.mfp-fade.mfp-wrap .mfp-content {
  opacity: 0;
  -webkit-transition: all 0.15s ease-out;
  -moz-transition: all 0.15s ease-out;
  transition: all 0.15s ease-out;
}
/* content animate it */
.mfp-fade.mfp-wrap.mfp-ready .mfp-content {
  opacity: 1;
}
/* content animate out */
.mfp-fade.mfp-wrap.mfp-removing .mfp-content {
  opacity: 0;
}</code></pre>



<p>I&#8217;ve also added extra &#8220;col&#8221; classes for my own grid styles when the viewport is decreased. Also notice the .mfp classes are necessary for our magnific popup to work &#8220;magnificently&#8221;.</p>



<h3 class="wp-block-heading">The HTML</h3>



<p>Finally, this is the file that we add to any page of our SharePoint site. Create a text file &#8211; name it &#8220;sp-gallery.txt&#8221; and add the code below:</p>



<pre class="wp-block-code"><code lang="markup" class="language-markup">&lt;script src="https://code.jquery.com/jquery-1.12.0.min.js"&gt;&lt;/script&gt;
&lt;script src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.0.5/handlebars.min.js"&gt;&lt;/script&gt;
&lt;script src="https://cdnjs.cloudflare.com/ajax/libs/magnific-popup.js/1.0.1/jquery.magnific-popup.min.js"&gt;&lt;/script&gt;
&lt;script src="ADD-YOUR-PATH-HERE/sp-gallery.js"&gt;&lt;/script&gt;
&lt;script&gt;
$(document).ready(function(){
  var photos = gallery('TestPhotoLib'); //change to your document library name
  photos.init();
  $('#showmore').on('click', photos.showmore);
})
&lt;/script&gt;
&lt;div class="photo-gallery-wrap"&gt;&lt;/div&gt;
&lt;div class="showMoreWrap"&gt;
&lt;a id="showmore" class="btn btn-sm btn-success" href="#"&gt;Show More&lt;/a&gt;&lt;/div&gt;</code></pre>



<p>&nbsp;<br>The above contains the references to the files we need.</p>



<p>We went ahead and create our gallery and pass in the name of our Photo Gallery above. We then initialize and add the &#8220;showmore&#8221; handler when our button is clicked.</p>



<p>Add our Handlebars template to the text file:</p>



<pre class="wp-block-code"><code lang="markup" class="language-markup">&lt;script id="photogallery" type="text/x-handlebars-template"&gt;
{{#each d}}
&lt;div class="col-lg-3 col-md-3 col-sm-3 col-xs-4 col-xxs-6 col-xxxs-12 thumbnail-wrap"&gt;
  &lt;a href="{{imgSrc this}}" group="{{findGroup this}}" class="thumbnail popup" style="background:url('{{imgSrcThumb this}}');" &gt;
    {{Name}}
  &lt;/a&gt;
&lt;/div&gt;
{{/each}}
&lt;/script&gt;</code></pre>



<p>&nbsp;<br>The above template is what we need for our gallery to work. This code represents each tile that we will produce in our gallery.</p>



<p>Save this text file (along with the .js and .css) and add it to any SharePoint page. Add a Content Editor WebPart, and add a link to an external file &#8211; to our .txt file.</p>



<p><br><img decoding="async" width="418" height="290" class="alignnone size-full wp-image-5482" src="https://michaelsoriano.com/wp-content/uploads/2016/02/sp-photo-gallery-2.jpg" alt="sp-photo-gallery-2" srcset="https://michaelsoriano.com/wp-content/uploads/2016/02/sp-photo-gallery-2.jpg 418w, https://michaelsoriano.com/wp-content/uploads/2016/02/sp-photo-gallery-2-300x208.jpg 300w" sizes="(max-width: 418px) 100vw, 418px" /><br>I usually edit the webpart to &#8220;NOT&#8221; show the chrome.</p>



<h3 class="wp-block-heading">Final Result</h3>



<p>Save the page and if everything works well, you should see something like below:</p>



<p><img decoding="async" width="602" height="480" class="alignnone size-full wp-image-5869" src="https://michaelsoriano.com/wp-content/uploads/2015/02/bspg.gif" alt="bspg"><br></p>



<p>A simple photo gallery with popup and paging functionality. It surely looks better than the &#8220;out of the box&#8221; photo gallery that SP provides. Furthermore, you have complete ability to change the look as much as you want.</p>



<p>But the real value is the introductory lesson to working with SharePoint&#8217;s REST api. Be sure to stay tuned for more stuff like this. </p>



<p>Leave your comments below.</p>
<p>The post <a href="https://michaelsoriano.com/better-photo-gallery-sharepoint-rest-and-handlebars/">Build a Better Photo Gallery for SharePoint using REST and Handlebars</a> appeared first on <a href="https://michaelsoriano.com">Michael Soriano</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://michaelsoriano.com/better-photo-gallery-sharepoint-rest-and-handlebars/feed/</wfw:commentRss>
			<slash:comments>47</slash:comments>
		
		
			</item>
		<item>
		<title>How to fully customize your Google Map Info Windows with Infobox</title>
		<link>https://michaelsoriano.com/customize-google-map-info-windows-infobox/</link>
					<comments>https://michaelsoriano.com/customize-google-map-info-windows-infobox/#comments</comments>
		
		<dc:creator><![CDATA[Michael Soriano]]></dc:creator>
		<pubDate>Fri, 04 Mar 2016 04:43:51 +0000</pubDate>
				<category><![CDATA[CSS]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[google maps]]></category>
		<category><![CDATA[Handlebars]]></category>
		<guid isPermaLink="false">http://michaelsoriano.com/?p=5499</guid>

					<description><![CDATA[<p>So I had a recent task of designing an infowindow for a Google map. Just in case you do not know, Google maps API has the ability of overlaying some HTML on top of a marker, also known as an &#8220;infowindow&#8220;. The problem is, the default infowindow has limited options for HTML styling. View Demo [&#8230;]</p>
<p>The post <a href="https://michaelsoriano.com/customize-google-map-info-windows-infobox/">How to fully customize your Google Map Info Windows with Infobox</a> appeared first on <a href="https://michaelsoriano.com">Michael Soriano</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>So I had a recent task of designing an infowindow for a Google map. Just in case you do not know, Google maps API has the ability of overlaying some HTML on top of a marker, also known as an &#8220;<a href="https://developers.google.com/maps/documentation/javascript/examples/infowindow-simple">infowindow</a>&#8220;. </p>



<p>The problem is, the default infowindow has limited options for HTML styling.</p>



<p class="btn"><a href="http://demo.michaelsoriano.com/infobox/">View Demo</a></p>



<p>The default infowindow looks like below:</p>



<p><img decoding="async" width="354" height="261" class="alignnone size-full wp-image-5511" src="https://michaelsoriano.com/wp-content/uploads/2016/03/regular.png" alt="regular" srcset="https://michaelsoriano.com/wp-content/uploads/2016/03/regular.png 354w, https://michaelsoriano.com/wp-content/uploads/2016/03/regular-300x221.png 300w" sizes="(max-width: 354px) 100vw, 354px" /></p>



<p>You can only style the inside of the window. We need a bit more flexibility and style the entire window. </p>



<p>Thankfully there&#8217;s this plugin called &#8220;<a href="http://google-maps-utility-library-v3.googlecode.com/svn/trunk/infobox/docs/examples.html">Infobox</a>&#8220;. With InfoBox, you can style the entire window by simply passing a few parameters. In my case, I need to make the window look like below:</p>



<p><img decoding="async" width="354" height="261" class="alignnone size-full wp-image-5519" src="https://michaelsoriano.com/wp-content/uploads/2016/03/modified2.jpg" alt="modified2" srcset="https://michaelsoriano.com/wp-content/uploads/2016/03/modified2.jpg 354w, https://michaelsoriano.com/wp-content/uploads/2016/03/modified2-300x221.jpg 300w" sizes="(max-width: 354px) 100vw, 354px" /></p>



<p>Ready to get started? Let&#8217;s start by adding our script to InfoBox. Note that if you&#8217;re loading Google Maps asynchronously, you need to add your script in your callback method.</p>



<pre class="wp-block-code"><code lang="javascript" class="language-javascript">var initMap = function() {
  var s = document.createElement("script");
  s.type = "text/javascript";
  s.src = "js/infobox.js";
  $("head").append(s);
  var map = new google.maps.Map(document.getElementById('map-wrap'), {
    center: {lat: 33.78444500, lng: -118.15378000},
    zoom: 8
  });
}</code></pre>



<p>Once your scripts are loaded, you should see your map, and add a simple marker like so:</p>



<pre class="wp-block-code"><code lang="javascript" class="language-javascript">var marker, i;
marker = new google.maps.Marker({
   position: new google.maps.LatLng(22.556444, -44.565),
   map: map
})</code></pre>



<p>Now, InfoBox has plenty of options &#8211; so I just leave the defaults alone. What we really need is the &#8220;boxStyle&#8221; object. This we can pass our CSS as key/value pairs. This is the style of the outermost box &#8211; the box that the default infowindow doesn&#8217;t let you customize easily.</p>



<pre class="wp-block-code"><code lang="javascript" class="language-javascript">var ibOptions = {
    		disableAutoPan: false
    		,maxWidth: 0
    		,pixelOffset: new google.maps.Size(-140, 0)
    		,zIndex: null
    		,boxStyle: {
          padding: "0px 0px 0px 0px",
          width: "252px",
          height: "40px"
        },
        closeBoxURL : "",
        infoBoxClearance: new google.maps.Size(1, 1),
    		isHidden: false,
    		pane: "floatPane",
    		enableEventPropagation: false
    	};</code></pre>



<p>Once that&#8217;s done, let&#8217;s create a click handler, so our InfoBox will pop out when our marker is clicked. The code below is an example of a closure. We&#8217;re only including the &#8220;non static&#8221; properties inside our closure, so you&#8217;ll notice that our &#8220;<em>innerHTML</em>&#8221; property is inside.</p>



<pre class="wp-block-code"><code class="">google.maps.event.addListener(marker, 'click', (function(marker, i) {
      return function() {
        var source   = $("#infobox-template").html();
        var template = Handlebars.compile(source);
        var boxText = document.createElement("div");
        boxText.style.cssText = "margin-top: 8px; background: #fff; padding: 0px;";
        boxText.innerHTML = template(subSet[i]);
        ibOptions.content = boxText
        var ib = new InfoBox(ibOptions);
      	ib.open(map, marker);
        map.panTo(ib.getPosition());
      }
  })</code></pre>



<p>I am also using <a href="http://handlebarsjs.com/">Handlebars</a> for templating, so the template is compiled multiple times. Also inside click handler above, and only shows up when the marker is actually clicked. My template will look like below. Remember that I have multiple of these boxes.</p>



<pre class="wp-block-code"><code lang="markup" class="language-markup">&lt;div class="info-box-wrap">
  &lt;img src="{{img_src}}" />
  &lt;div class="info-box-text-wrap">
  &lt;h6 class="address">{{address}}, {{city}} {{zip}} {{state}}&lt;/h6>
  &lt;p class="price">{{price}}&lt;/p>
&lt;/div>
&lt;div class="action-btns">&lt;/div>
&lt;/div></code></pre>



<p>Finally, the styles. Remember, InfoBox has already done the outer shell styles. Now it&#8217;s up to us to style the inner part of our box. So simply hack away with your CSS chops:</p>



<pre class="wp-block-code"><code lang="css" class="language-css">.info-box-wrap {
  background:#fff;
  overflow: hidden;
  box-shadow: 5px 5px 0px rgba(0, 0, 0, 0.08);
}
.info-box-text-wrap {
  height:40px !important;
  width:120px;
  float:left;
  overflow: hidden;
}
.action-btns {
  float:left;
  width:70px;
  overflow: hidden;
  position: relative;
  top:12px;
  left: 6px;
}
.action-btns i {
  font-size: 18px;
  color: #78A737;
  margin-left: 3px;
}
.action-btns i:hover {
  transition: color 0.5s ease;
  color:#ccc;
  cursor: pointer;
}
.action-btns i.fa-heart-o {
  font-weight: bold;
}
.info-box-text-wrap h6.address {
  padding:6px 5px 1px 0;
  margin:0 0 0 0;
  font-family:"Roboto Slab";
  color: #0c99c8;
  font-weight: 700;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.info-box-text-wrap p {
  padding:0 0 0 0;
  margin:0 0 0 0;
}
.info-box-text-wrap p.price {
  color:#B25B00;
}
.info-box-wrap  img {
  width:40px !important;
  height:40px;
  float:left;
  margin-right: 10px;
  padding-top:0;
  margin-top:0;
}</code></pre>



<p>With the above code everything should be in place. All we need is an arrow that points back from our box to our marker.</p>



<h3 class="wp-block-heading">Creating the Arrow</h3>



<p>There is an awesome article on how to create <a href="https://css-tricks.com/snippets/css/css-triangle/">traingles</a> that is pure CSS. We really don&#8217;t need an image for this type of thing. Another thing, we&#8217;re going to use the <strong>::before</strong> pseudo selector to insert our triangle. This prevents us from adding unnecessary DIVs into our markup.</p>



<pre class="wp-block-code"><code lang="css" class="language-css">.infoBox:before{
  content : " ";
  width: 0;
  height: 0;
  border-left: 10px solid transparent;
  border-right: 10px solid transparent;
  border-bottom: 10px solid #fff;
  position:absolute;
  top:-10px;
  left:130px;
}</code></pre>



<p>Note the &#8220;content&#8221; property with the value of &#8221; &#8220;. This makes it so the ::before selector is actually visible in the DOM.</p>



<p>And the final result looks like below. Note that the map automatically centers to the marker that is clicked. That is in our click handler &#8220;<em>map.panTo(ib.getPosition())</em>&#8221; method.</p>



<p><img decoding="async" width="489" height="293" class="alignnone size-full wp-image-5520" src="https://michaelsoriano.com/wp-content/uploads/2016/03/infobox2.gif" alt="infobox2"></p>



<p>Note that in the <a href="http://demo.michaelsoriano.com/infobox/">demo</a>, it&#8217;s loading sample data from a text file. I&#8217;m also outputting which property is clicked on the left side.</p>



<p>Until next time, please leave your comments below.</p>
<p>The post <a href="https://michaelsoriano.com/customize-google-map-info-windows-infobox/">How to fully customize your Google Map Info Windows with Infobox</a> appeared first on <a href="https://michaelsoriano.com">Michael Soriano</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://michaelsoriano.com/customize-google-map-info-windows-infobox/feed/</wfw:commentRss>
			<slash:comments>21</slash:comments>
		
		
			</item>
	</channel>
</rss>
