All posts tagged JavaScript

  • Creating New Conditionals in Handlebars

    If you work with Handlebars long enough, you’ll start to notice a very annoying gap in its capabilities: conditionals. Now, Handlebars does come with a conditionals helper that simply tests whether or not the passed in value is truthy or not and acts accordingly. While this is fine for a good portion of scenarios, I guarantee there will come a time where you need a more robust solution. Today, we’re going to go over three conditional helpers that handlebars is lacking and how to make them yourself.

    EqualTo

    Handlebars.registerHelper('ifequal', function(value1, value2, options) {
      if(value1 === value2) {
        return options.fn(this);
      }
      return options.inverse(this);
    });
    

    LessThan and LessThanOrEqual

    Handlebars.registerHelper('iflessthan', function(value1, value2, options) {
      if(value1 < value2) {
        return options.fn(this);
      }
      return options.inverse(this);
    });
    
    Handlebars.registerHelper('iflessthanorequal', function(value1, value2, options) {
      if(value1 <= value2) {
        return options.fn(this);
      }
      return options.inverse(this);
    });
    

    If you need additional functionality (e.g., greater-than-or-eaual-to or not-equal-to), you can easily figure out what needs to be done given the examples provided. If you don’t feel like creating individual helpers for each kind of conditional, I found this really cool snippet on StackOverflow that may come in handy:

    Handlebars.registerHelper('ifCond', function (v1, operator, v2, options) {
    
        switch (operator) {
            case '==':
                return (v1 == v2) ? options.fn(this) : options.inverse(this);
            case '===':
                return (v1 === v2) ? options.fn(this) : options.inverse(this);
            case '<':
                return (v1 < v2) ? options.fn(this) : options.inverse(this);
            case '<=':
                return (v1 <= v2) ? options.fn(this) : options.inverse(this);
            case '>':
                return (v1 > v2) ? options.fn(this) : options.inverse(this);
            case '>=':
                return (v1 >= v2) ? options.fn(this) : options.inverse(this);
            case '&&':
                return (v1 && v2) ? options.fn(this) : options.inverse(this);
            case '||':
                return (v1 || v2) ? options.fn(this) : options.inverse(this);
            default:
                return options.inverse(this);
        }
    });
    

    You use it like this:

    {{#ifCond var1 '==' var2}}
    
  • JsLint Unexpected Continue Error Explained

    If you’ve ever had the “pleasure” of running your JavaScript code through JSLint, you’ve probably encounter the following message.

    Unexpected continue

    Recently, I encountered this message when checking some code I’d written. In an attempt to gain some clarity on what the problem was, I checked out the JS Lint Documentation which tells me to

    [a]void use of the continue statement. It tends to obscure the control flow of the function.

    Read more

  • Using Handlebars “Each” Blocks with Backbone Collections / Templates

    A while back I took Code School’s amazing course on Backbone.js. In one of the slides, I found this block of code:

    var TodoListView = Backbone.View.extend({
      initialize: function(){
        this.collection.on('add', this.addOne, this);
        this.collection.on('reset', this.addAll, this);
      },
      addOne: function(todoItem){
        var todoView = new TodoView({model: todoItem});
        this.$el.append(todoView.render().el);
      },
      addAll: function(){
        this.collection.forEach(this.addOne, this);
      },
      render: function(){
        this.addAll();
      }
    });
    

    For the most part, it’s pretty straight forward. Basically, they are calling the addOne method and passing in the model they want to add to the list view. In the context of the lesson, they were trying to show how you might go about looping through a collection of items and adding them to a list while avoiding issues related to scope.

    Read more

  • Element.dataset not supported in IE: Here’s a Workaround

    Recently, I was working on a project that used the dataset property to store some additional info about element and I discovered that none of my code worked in IE. After doing some research, I found out that dataset property is not supported by IE (at least not until version 11 comes out). If you’ve ever run into this issue, here’s a quick workaround:

    var myElement = document.getElementById('myElement'), // contains attribute data-my-custom-value
        myCustomValue;
    
    if(myElement.dataset !== undefined) { // standard approach
        myCustomValue = myElement.dataset.myCustomValue;
    } else {
        myCustomValue = myElement.getAttribute('data-my-custom-value'); // IE approach
    }
    

    In the above example, if the dataset property is undefined, we use the getAttribute method to grab it instead. The one thing to note here is that when you use dataset property to retrieve the value of the my-custom-value attribute, the name of the attribute gets converted to camel-case and the “data” portion of the name is dropped; when you use getAttribute the value is retrieved using the original hyphened value.

  • Chrome Not Autoplaying Video Stream in Canvas

    I was recently tinkering with some demo code that David Walsh put together and, after setting up my own demo using the code mentioned in the post, I noticed some odd behavior in Chrome. Whenever you loaded the page and gave Chrome permission to access your webcam, the camera stream would not show up until you triggered a repaint on the page (e.g., resizing the developer toolbar or clicking the “snap picture” button). While I don’t really understand why this is the case, I did figure out a way to fix it:

    Read more

  • Code Snippet: How to Sort An Array of JSON Objects By Property

    While working on another project, I ran into a situation where I needed to sort an array of JSON objects. Now, for those of you who may be new to JavaScript, the array.sort method allows you to pass in a custom sort function that is meant to look something like this:

    Read more

  • Code Snippet: Prevent Flickering When Enforcing Maxlength on Textareas

    I was doing some research today regarding how to limit the number of characters on the page while removing the annoying flickering effect that often occurs with JavaScript-based solutions to the problem. Here’s what I came up with:
    Read more

  • A Helpful Guide to Moving Away From jQuery (Via the Lonely Coder)

    Recently, I wrote a post about how jQuery’s prevalence on the web was causing web developers to learn less JavaScript and more jQuery due to how it conceals many of the more complicated inner workings of JavaScript in wrapper methods like bind and ready.

    Michael Enger over at The Lonely Coder seems to agree with me and he put together a really cool guide on how to replace some of the more common jQuery methods with their native JavaScript counterparts. In addition to going over how to replace ready and how to do event delegation, he does an excellent job of covering CSS selectors. From the guide:

    One of the greatest benefits of jQuery is to be able to drill down into the DOM by using CSS-style selector strings to specify which element you’re looking for. Something as complicated as “#app ul .title a:hover > span.left” can be used to choose one specific element, or a set of elements that are situated in various places around the document. Unfortunately there isn’t a direct replacement in native JavaScript, but a combination of getElementById, getElementsByTagName and getElementsByClassName, as well as iterating through the results, can be used to select the element(s) you need and not being able to rely on CSS pseudo-classes or some of the more esoteric selectors may result in structuring the HTML in a less convoluted way, avoiding unnecessary strain on the browser who has to deal with all your crazy shenanigans.

    // Get the data-foo attribute of all links inside a .button list
    var buttons = document.getElementsByClassName('buttons'),
        foo = '';
    for (var i = 0; i < buttons.length; i++) {
        var links = buttons[i].getElementsByTagName('a');
        for (var j = 0; j < links.length; j++) {
            var link = links[j];
            foo += link.attributes['data-foo'];
        }
    }
    

    Edit: My good friend Torjus Bjåen made me aware of the querySelectorAll function, which provides the same CSS-style selector capabilities that jQuery does, albeit without some of the more “magical” selectors. It works like you’d expect and can be used to easily fetch elements that may be spread about the DOM.

    var links = document.querySelectorAll('.buttons a.special');
    for (var i = 0; i < links.length; i++) {
        links[i].style.backgroundColor = '#f09';
    }
    

    I highly suggest you check out his guide, it’s an excellent starting place for those looking to move away from jQuery and to a more native approach.

  • Why Array.Splice Belongs With Push, Pop, Shift, and Unshift

    If you take a look at tutorials about JavaScript adding and removing items from an array, you’ll see four methods mentioned: Push, Pop, Shift, and Unshift. If you’re new to JavaScript or need a refresher, here’s a quick breakdown of each of those methods.

    Push

    Definition: Mutates an array by appending the given elements and returning the new length of the array. This method changes the length of the array.

    Read more

  • How to “Detect” If Your CDN is Down And Load a Script Locally As Backup

    I’m sure this has been around for a while now, but I just stumbled upon it and found it interesting:

    ...
    <script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
    <script>
    window.jQuery || document.write('<script src="js/vendor/jquery-1.9.1.min.js"><\/script>')</script>
    ...
    

    Basically, this does a check to see if jQuery has loaded properly from the CDN and, if it hasn’t, it tries to load it locally.