Blog

Tagged by 'javascript'

  • There will be times where you will want to customise the slug based on fields from your markdown file. In my case, I wanted all my blog post URL's in the following format: /Blog/yyyy/MM/dd/Blog-Post-Title. There are two ways of doing this:

    1. Enter the full slug using a “slug” field within your markdown file.
    2. Use the onCreateNode() function found in the gatsby-node.js file to dynamically generate the slug.

    My preference would be option 2 as it gives us the flexibility to modify the slug structure in one place when required. If for some reason we had to update our slug structure at a later date, it would be very time consuming (depending on how many markdown files you have) to update the slug field within each markdown file if we went ahead with option 1.

    This post is suited for those who are storing their content using markdown files. I don’t think you will get much benefit if your Gatsby site is linked to a headless CMS, as the slugs are automatically generated within the platform.

    The onCreateNode() Function

    This function is called whenever a node is created or updated, which makes it the most ideal place to add the functionality we want to perform. It is found in the gatsby-node.js file

    What we need to do is retrieve the fields we would like to form part of our slug by accessing the nodes frontmatter. In our case, all we require is two fields:

    1. Post Date
    2. Slug
    exports.onCreateNode = ({ node, actions, getNode }) => {
        const { createNodeField } = actions
      
        if (node.internal.type === `MarkdownRemark`) {
          const relativeFilePath = createFilePath({ node, getNode, trailingSlash: false });
          const postDate = moment(node.frontmatter.date); // Use moment.js to easily change date format.
          const url = `/Blog/${postDate.format("YYYY/MM/DD")}${node.frontmatter.slug}`;
    
          createNodeField({
            name: `slug`,
            node,
            value: url,
          });
        }
      }
    

    After making this change, you will need to re-run the gatsby develop command.

  • I've been doing some personal research into improving my own JavaScript development. I decided to get more familiar with the new version of JavaScript - ES6. ES6 is filled to the brim with some really nice improvements that make JavaScript development much more concise and efficient. After having the opportunity to work on React and React Native projects, I had a chance in putting my new found ES6 knowledge to good use!

    If I had to describe ES6 in a sentence:

    JavaScript has gone on a diet and cut the fat. Write less, do more!

    I have only scratched the surface to what ES6 has to offer and will continue to add more to the list as I learn. If you are familiar with server-side development, you might notice some similarities from a syntax perspective. That in itself shows how far ES6 has pushed the boundaries.

    Arrow Functions

    Arrow functions are beautiful and so easy on the eye when scrolling through vast amounts of code. You'll see with arrow functions, you'll have the option to condense a function that consists of many lines all the way down to single line.

    The traditional way we are all familiar with:

    // The "old school" way..
    function addSomeNumbers(a, b) {
        return a + b;
    }
    
    console.log(addSomeNumbers(1, 2));
    // Output: 3
    

    ES6:

    // ES6.
    const addSomeNumbers = (a, b) => {
        return a + b;
    }
    
    console.log(addSomeNumbers(1, 2));
    // Output: 3
    

    The traditional and ES6 way can still be used in the same way to achieve our desired output. But we can condense out arrow function further:

    // Condensed ES6 arrow function.
    const addSomeNumbers = (a, b) => a + b;
    
    console.log(addSomeNumbers(1, 2));
    // Output: 3
    

    Default Function Parameters

    When developing using server-side languages, such as C# you have the ability to set default values on the parameters used for your functions. This is great, since you have more flexibilty in using a function over a wider variety of circumstances without the worry of compiler errors if you haven't satisfied all function parameters.

    Lets expand our "addSomeNumbers()" function from our last section to use default parameters.

    // Condensed ES6 arrow function with default parameters.
    const addSomeNumbers = (a=0, b=0) => a + b;
    
    console.log(addSomeNumbers());
    // Output: 0
    

    This is an interesting (but somewhat useless) example where I am using "addSomeNumbers()" function without passing any parameters. As a result the value 0 is returned and even better - no compiler error.

    Destructuring

    Destructuring sounds scary and complex. In its simple terms, destructuring is the process of adding values to an object or array to an existing variable more straightforward. Lets start of with a simple object and how we can output these values:

    // Some info on my favourite Star Trek starship...
    const starship = {
      registry: "NCC-1701-E",
        captain: "Jean Luc Picard",
        launch_date: "October 30, 2372",
        spec: {
          max_warp: 9.995,
          mass: "3,205,000 metric tons",
          length: "685.7 meters",
          width: "250.6 meters",
          height: "88.2 meters"
      }
    };
    

    We would normally output the these values in the following way:

    var registry = starship.registry; // Output: NCC-1701-E
    var captain = starship.captain; // Output: Jean Luc Picard
    var launchDate = starship.launch_date; // Output: October 30, 2372
    

    This works well, but the process of returning those values is a little repetitive and spread over many lines. Lets get a bit more focus and go down the ES6 route:

    const { registry, captain, launch_date } = starship;
    
    console.log(registry); // Output: NCC-1701-E 
    

    How amazing is that? We've managed to select a handful of these fields on one line to do something with.

    My final example in the use of destructuring will evolve around an array of items - in this case names of starship captains:

    const captains = ["James T Kirk", "Jean Luc Picard", "Katherine Janeway", "Benjamin Sisko"]
    

    Here is how I would return the first two captains in ES5 and ES6:

    // ES5
    var tos = captains[0];
    var tng = captains[1];
    
    // ES6
    const [tos, tng ] = captains;
    

    You'll see similarities to our ES6 approach for getting the values out of an array as we did when using an object. The only thing I need to look into is how to get the first and last captain from my array? Maybe that's for a later post.

    Before I end the destructuring topic, I'll add this tweet - a visual feast on the basis of what destructuring is...

    Destructuring. Courtesy of @NikkitaFTW pic.twitter.com/j8OX3VyrTL
    — Burke Holland (@burkeholland) May 31, 2018

    Spread Operator

    The spread operator has to be my favourite ES6 feature, purely because in my JavaScript applications I do a lot of data manipulation. If you can get your head around destructuring and the spread operator, you'll find working with data a lot easier. A spread operator is "...". Yes three dots - ellipsis if you prefer. This allows you to copy the values of an object to be used as a basis of a new object.

    In its basic form:

    const para1 = ["to", "boldly", "go"];
    const para2 = [...para1, "where", "no", "one"];
    const para3 = [...para2, "has", "gone", "before"];
    
    console.log(para1); // Output: ["to", "boldly", "go"]
    console.log(para2); // Output: ["to", "boldly", "go", "where", "no", "one"]
    console.log(para3); // Output: ["to", "boldly", "go", "where", "no", "one", "has", "gone", "before"]
    

    As you can see from my example above, the spread operator used on variables "para1" and "para2" creates a shallow copy of the array values into our new array. Gone are the days of having to use a for loop to get the values.

  • For one of my side projects, I was asked to use Butter CMS to allow for basic blog integration using JavaScript. I have never heard or used Butter CMS before and was intrigued to know more about the platform.

    Butter CMS is another headless CMS variant that allows a developer to utilise API endpoints to push content to an application via an arrange of approaches. So nothing new here. Just like any headless CMS, the proof is in the pudding when it comes to the following factors:

    • Quality of features
    • Ease of integration
    • Price points
    • Quality of documentation

    I haven't had a chance to properly look into what Butter CMS fully has to offer, but from what I have seen from working on the requirements for this side project I was pleasently surprised. Found it really easy to get setup with minimal amount of fuss! For this project I used Butter CMS's Blog Engine package, which does exactly what it says on the tin. All the fields you need for writing blog posts are already provided.

    JavaScript Code

    My JavaScipt implementation is pretty basic and provides the following functionality:

    • Outputs a list of posts consisting of title, date and summary text
    • Pagination
    • Output a single blog post

    All key functionality is derived from the "ButterCMS" JavaScript file:

    /*****************************************************/
    /*                    Butter CMS                                 */
    /*****************************************************/
    var ButterCMS =
    {
        ButterCmsObj: null,
    
        "Init": function () {
            // Initiate Butter CMS.
            this.ButterCmsObj = new ButterCmsBlogData();
            this.ButterCmsObj.Init();
        },
        "GetBlogPosts": function () {
            BEButterCMS.ButterCmsObj.GetBlogPosts(1);
        },
        "GetSinglePost": function (slug) {
            BEButterCMS.ButterCmsObj.GetSinglePost(slug);
        }
    };
    
    /*****************************************************/
    /*                Butter CMS Data                         */
    /*****************************************************/
    function ButterCmsBlogData() {
        var apiKey = "<Enter API Key>",
            baseUrl = "/",
            butterInstance = null,
            $blogListingContainer = $("#posts"),
            $blogPostContainer = $("#post-individual"),
            pageSize = 10;
    
        // Initialise of the ButterCMSData object get the data.
        this.Init = function () {
            getCMSInstance();
        };
    
        // Returns a list of blog posts.
        this.GetBlogPosts = function (pageNo) {
            // The blog listing container needs to be cleared before any new markup is pushed.
            // For example when the next page of data is requested.
            $blogListingContainer.empty();
    
            // Request blog posts.
            butterInstance.post.list({ page: pageNo, page_size: pageSize }).then(function (resp) {
                var body = resp.data,
                    blogPostData = {
                        posts: body.data,
                        next_page: body.meta.next_page,
                        previous_page: body.meta.previous_page
                    };
    
                for (var i = 0; i < blogPostData.posts.length; i++) {
                    $blogListingContainer.append(blogPostListItem(blogPostData.posts[i]));
                }
    
                //----------BEGIN: Pagination--------------//
    
                $blogListingContainer.append("<div>");
    
                if (blogPostData.previous_page) {
                    $blogListingContainer.append("<a class=\"page-nav\" href=\"#\" data-pageno=" + blogPostData.previous_page + " href=\"\">Previous Page</a>");
                }
    
                if (blogPostData.next_page) {
                    $blogListingContainer.append("<a class=\"page-nav\" href=\"#\" data-pageno=" + blogPostData.next_page + " href=\"\">Next Page</a>");
                }
    
                $blogListingContainer.append("</div>");
    
                paginationOnClick();
    
                //----------END: Pagination--------------//
            });
        };
    
        // Retrieves a single blog post based on the current URL of the page if a slug has not been provided.
        this.GetSinglePost = function (slug) {
            var currentPath = location.pathname,
                blogSlug = slug === null ? currentPath.match(/([^\/]*)\/*$/)[1] : slug;
    
            butterInstance.post.retrieve(blogSlug).then(function (resp) {
                var post = resp.data.data;
    
                $blogPostContainer.append(blogPost(post));
            });
        };
    
        // Renders the HTML markup and fields for a single post.
        function blogPost(post) {
            var html = "";
    
            html = "<article>";
    
            html += "<h1>" + post.title + "</h1>";
            html += "<div>" + blogPostDateFormat(post.created) + "</div>";
            html += "<div>" + post.body + "</div>";
            
            html += "</article>";
    
            return html;
        }
    
        // Renders the HTML markup and fields when listing out blog posts.
        function blogPostListItem(post) {
            var html = "";
    
            html = "<h2><a href=" + baseUrl + post.url + ">" + post.title + "</a></h2>";
            html += "<div>" + blogPostDateFormat(post.created) + "</div>";
            html += "<p>" + post.summary + "</p>";
    
            if (post.featured_image) {
                html += "<img src=" + post.featured_image + " />";
            }
    
            return html;
        }
    
        // Set click event for previous/next pagination buttons and reload the current data.
        function paginationOnClick() {
            $(".page-nav").on("click", function (e) {
                e.preventDefault();
                var pageNo = $(this).data("pageno"),
                    butterCmsObj = new ButterCmsBlogData();
    
                butterCmsObj.Init();
                butterCmsObj.GetBlogPosts(pageNo);
            });
        }
    
        // Format the blog post date to dd/MM/yyyy HH:mm
        function blogPostDateFormat(date) {
            var dateObj = new Date(date);
    
            return [dateObj.getDate().padLeft(), (dateObj.getMonth() + 1).padLeft(), dateObj.getFullYear()].join('/') + ' ' + [dateObj.getHours().padLeft(), dateObj.getMinutes().padLeft()].join(':');
        }
    
        // Get instance of Butter CMS on initialise to make one call.
        function getCMSInstance() {
            butterInstance = new Butter(apiKey);
        }
    }
    
    // Set a prototype for padding numerical values.
    Number.prototype.padLeft = function (base, chr) {
        var len = (String(base || 10).length - String(this).length) + 1;
    
        return len > 0 ? new Array(len).join(chr || '0') + this : this;
    };
    

    To get a list of blog posts:

    // Initiate Butter CMS.
    BEButterCMS.Init();
    
    // Get all blog posts.
    BEButterCMS.GetBlogPosts();
    

    To get a single blog post, you will need to pass in the slug of the blog post via your own approach:

    // Initiate Butter CMS.
    BEButterCMS.Init();
    
    // Get single blog post.
    BEButterCMS.GetSinglePost(postSlug);
    
  • Postbacks can be annoying. Especially when you have a long page of content with a form at the bottom and on button click causes the page to skip back to the top of the page.

    For a user who is not used to a site, this can be incredibly annoying and disorientating simply due to the fact the page has moved to a different position. This isn't so much of an issue if you happen to have a webpage that is low on content and a form will always be in clear view.

    But there is quite a nice easy way to get back to a specific area of a page by using the following line of JavaScript will be added in the page after a postback has occurred.

    if (Page.IsPostBack)
    {
        ScriptManager.RegisterStartupScript(this, typeof(string), "PostbackFocus", "window.location.hash = 'feedback-form'", true);
    }
    

    By placing this code in your Page_Load method, the user will be taken to an anchor point placed within the page. In this case, a <div> with an ID attribute of "feedback-form".

  • Safari iOS6It wasn’t until today I found that the Safari browser used on iPad and iPhone caches page functionality to such an extent that it stops the intended functionality. So much so, it affects the user experience. I think Apple has gone a step too far in making their browser uber efficient to minimise page loading times.

    We can accept browsers will cache style-sheets and client side scripts. But I never expected Safari to go as far as caching responses from web services. This is a big issue. So something as simple as the following will have issues in Safari:

    // JavaScript function calling web service
    function GetCustomerName(id)
    {
        var name = "";
    
        $.ajax({
            type: "POST",
            url: "/Internal/ShopService.asmx/GetCustomerName",
            data: "{ 'id' : '" + id + "' }",
            contentType: "application/json; charset=utf-8",
            dataType: "json",
            cache: false,
            success: function (result) {
                var data = result.d;
                name = data;
            },
            error: function () {
            },
            complete: function () {
            }
        });
        
        return name;
    }
    
    //ASP.NET Web Service method
    [WebMethod]
    public string GetCustomerName(int id)
    {
       return CustomerHelper.GetFullName(id);
    }
    

    In the past to ensure my jQuery AJAX requests were not cached, the “cache: false” option within the AJAX call normally sufficed. Not if you’re making POST web service requests. It’s only until recently I found using “cache:false” option will not have an affect on POST requests, as stated on jQuery API:

    Pages fetched with POST are never cached, so the cache and ifModified options in jQuery.ajaxSetup() have no effect on these requests.

    In addition to trying to fix the problem by using the jQuery AJAX cache option, I implemented practical techniques covered by the tutorial: How to stop caching with jQuery and JavaScript.

    Luckily, I found an informative StackOverflow post by someone who experienced the exact same issue a few days ago. It looks like the exact same caching bug is still prevalent in Apple’s newest operating system, iOS6*. Well you didn’t expect Apple to fix important problems like these now would you (referring to Map’s fiasco!). The StackOverflow poster found a suitable workaround by passing a timestamp to the web service method being called, as so (modifying code above):

    // JavaScript function calling web service with time stamp addition
    function GetCustomerName(id)
    {
        var timestamp = new Date();
    
        var name = "";
    
        $.ajax({
            type: "POST",
            url: "/Internal/ShopService.asmx/GetCustomerName",
            data: "{ 'id' : '" + id + "', 'timestamp' : '" + timestamp.getTime() + "' }", //Timestamp parameter added.
            contentType: "application/json; charset=utf-8",
            dataType: "json",
            cache: false,
            success: function (result) {
                var data = result.d;
                name = data;
            },
            error: function () {
            },
            complete: function () {
            }
        });
        
        return name;
    }
    
    //ASP.NET Web Service method with time stamp parameter
    [WebMethod]
    public string GetCustomerName(int id, string timestamp)
    {
        string iOSTime = timestamp;
        return CustomerHelper.GetFullName(id);
    }
    

    The timestamp parameter doesn’t need to do anything once passed to web service. This will ensure every call to the web service will never be cached.

    *UPDATE: After further testing it looks like only iOS6 contains the AJAX caching bug.

  • We all know minimising our JavaScript files prior to moving a site into a production environment is best practise. The main reason why we do it is because compressed JavaScript files allow sites run faster at a lower bandwidth cost and (to some extent) make the code harder to understand.

    But what if we wanted to have the ability to render a JavaScript file completely unintelligible to prying eyes? This is the very question I asked myself prior to deploying a site I worked on to a live environment.

    Even though standard JavaScript minimisers remove comments, white space and use shorter variable names, we can take things a step further.

    I found a great site that manages to render your code into complete jibberish. You can give it a go by going to: http://javascriptobfuscator.com/.

    NOTE: Just as JavaScript code can be easily minimised, it can just as easily be “beautified” by going to: http://jsbeautifier.org/. Nevertheless, using the link above is a better deterrent when compared to other minimisers in my opinion.

  • Published on
    -
    1 min read

    String.Format In JavaScript

    Whenever I work with strings whilst programming in .NET, somewhere along the lines I always find myself using the awesome “string.format”. I think all of you will admit its the most useful and easiest way to build up your strings.

    The only downside to using the “string.format” method is that it lures you into a false sense of security and you find yourself lost without it when it comes to working with strings in other languages. This happened to me when I had to build up a long string in JavaScript. It was long and tedious…or maybe I am just lazy.

    Luckily, there have been a few developers who extended the string object in JavaScript to include “string.format”. Amazing! Its goes along the lines of adding this to your own JavaScript code:

    String.format = String.prototype.format = function() {
        var i=0;
        var string = (typeof(this) == “function” && !(i++)) ? arguments[0] : this;
    
        for (; i < arguments.length; i++)
            string = string.replace(/\{\d+?\}/, arguments[i]);
    
        return string;
    }
    

    Here are some other useful links I have found on how to implement “string.format” into your JavaScript code:

  • I have been building a custom .NET web part page to use in my SharePoint intranet. The .NET page has quite a lot of custom HTML and jQuery design elements, so using CSS and JavaScript files were essential.

    As you know, when we want to use elements from our CSS and JavaScript files we normally add the following lines of HTML at the top of our page:

    <!-- CSS -->
    <link type="text/css" rel="stylesheet" href="site.css" />
    
    <!-- JavaScript -->
    <script src="jQuery.js" type="text/javascript" />
    

    If you added those lines of code in a custom SharePoint page, you’ll find that the page will ignore them. Thankfully, SharePoint has given us some controls to add these references.

    At this point its worth stating that I stored all my required JavaScript and CSS files within the “Style Library” directory situated in the root of any SharePoint 2010 intranet. In order to get these files I used controls called”CssRegistration” and “ScriptLink”:

    <!-- CSS -->
    <SharePoint:CssRegistration ID="CssRegistration1" Name="/Style Library/Home/CSS/jcarousel.css" runat="server" After="corev4.css" />
    
    <!-- JavaScript -->
    <SharePoint:ScriptLink ID="ScriptLink1" Name="~sitecollection/Style Library/Home/JS/jquery-1.4.4.min.js" runat="server" />
    

    If you have stored your CSS and JavaScript within the physical file directory situated in the 14 hive folder, you will need to modify the above example to the following:

    <!-- CSS -->
    <SharePoint:CSSRegistration Name="<% $SPUrl:~SiteCollection/Style Library/Core Styles/jcarousel.css%>" runat="server"/>
    
    <!-- JavaScript -->
    <SharePoint:ScriptLink ID="ScriptLink1" Name="<% $SPUrl:~SiteCollection/Style Library/Core Styles/jquery.js%>" runat="server" />
    

    The only difference between this example and our earlier example is that when we have just added “SPUrl” to get files relative to the current site collection.

  • Web browsers have come a long way since the days of Internet Explorer 6 release back in 2001. You would think 9 years on we would have all dumped this piece of software in the garbage heap by now. Alas, we still have users to this very date who still use IE6 either due to personal preference or by force (company IT policies).

    As everyone knows, developing a site to be compliant with main stream browsers in addition to carrying out additional fixes to fit in with the slim 6.7% of global users can be a real pain. So instead of trying to fit your site around the small number of IE6 users, why not just knock some common sense into them and notify them to upgrade.

    Thankfully, there is a really easy and polite way to do this. Go to http://code.google.com/p/ie6-upgrade-warning/ and download the JavaScript file and embed the following code to your webpage…

    <!--[if lte IE 6]>
        <script src="js/ie6/warning.js"></script>
        <script>window.onload=function(){e("js/ie6/")}</script>
    <![endif]-->
    

    …which outputs the following result:

    IE6 Upgrade Warning

    As great as this idea is I don’t see many web developers or web agencies implementing this on the sites they create unless really needed. Nevertheless, its step in the right direction to hopefully put a final nail into that IE6 coffin!

  • Over the last few months I have had the ability to mess around with a bit of jQuery. Even though I don’t have the complete understanding on how it works, I can see the benefits of writing my code in jQuery compared to bashing out lots of lines of JavaScript to do the same thing.

    One the cool features I have used is calling one of my .NET methods using the “$.ajax” jQuery command. In my example (below), I have created two aspx pages. The code-behind of my first page  (jQueryMethodTest.aspx) will only contain a public static method called “WhatIsYourName”, which returns a string value.

    [WebMethod]
    public static string WhatIsYourName(string name)
    {
        if (!String.IsNullOrEmpty(name))
        {
            return String.Concat("Hello ", name, "!");
        }
        else
        {
            return String.Empty;
        }
    }
    

    Remember, the jQueryMethodTest.aspx page only needs to contain our method nothing else! Additional methods can be added. Just don’t add any web controls.

    The second page (jQueryAjax.aspx), will contain our jQuery code and some HTML to output our result from calling the “WhatIsYourName” method.

    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
        <title></title>
        <script type="text/javascript" language="javascript" src="javascript/jquery.js"></script>
    </head>
    <script type="text/javascript">
        $(document).ready(function() {
            $("#btnSubmitName").click(function(event) {
                $.ajax({
                    type: "POST",
                    url: "jQueryMethodTest.aspx/WhatIsYourName",
                    data: "{'name': '" + $('#name').val() + "'}",
                    contentType: "application/json; charset=utf-8",
                    dataType: "json",
                    success: function(message) {
                        ShowPopup(message);
                    },
                    error: NameFailed
                });
            });
        });
    
        function ShowPopup(result) {
            if (result.d != "") {
                $("#Message").html(result.d);
            }
            else {
                $("#Message").html("I didn't get your name.");
            }
        }
    
        function NameFailed(result) {
            $("#Message").html(result.status + ' ' + result.statusText);
        }  
      </script>  
    
    <body>
        <form id="form1" runat="server">
        <div>
            <input id="name" name="name" type="text" />
            <br />
            <input id="btnSubmitName" name="btnSubmitName" type="button" value="Submit" />
            <br /><br />
            <span id="Message" style="color:Red;"></span>
        </div>
        </form>
    </body>
    </html>
    

    If all goes well, you should get the following result:

    Calling ASP Method Using jQuery

    The “$.ajax” jQuery command requires the following parameters in order to work:

    • url – links to where our .NET method is placed.
    • data – retrieves the value from some control in our page to pass to our method. Remember, the name of the parameter must be named the same as the parameter from our .NET method.
    • dataType – the response type.
    • contentType – the request content type.
    • success – the JavaScript function that gets fired on postback.
    • error – the Javascript function that gets fired if there is a failure. This is an optional parameter.

    I guess jQuery’s motto really is true: “write less, do more”.