Friday, November 22, 2013

Formatting Dates with Moment as Backbone Computed Fields

I've gotten a little sloppy lately with my templates. Instead of formatting my dates outside of the template, I've been using Moment in the template to render different representations of the date value. The practice itself is really not the best approach. There's a good change you'll show the same value several times which requires redundant moment.format() calls. Additionally, it adds more code to a template when less is really a better choice. And finally, Moment 2.4.0 has started the process of deprecating the global scope reference in favor of defining it via an AMD library like RequireJS.

So the goal is to go from the less desirable:


   <%= moment( when ).format( 'MM/DD/YYYY' ) %>



To a value that has been already computed in the model:


   <%= when_fmt_short %>



My first thought was to just tie into the change event on a date field when initializing the model and write a function to generate all the different formats I might want to use:


var myModel = Backbone.Model.extend({

   defaults: {

      when: null,

   },

   initialize: function() {

      this.on( 'change:when', this.formatWhen );
      this.formatWhen();
   },

   formatWhen: function() {

      var val = this.get( 'when' );

      if ( val ) {
         val = moment( val );
         this.set( 'when_fmt_short', val.format('MM/DD/YYYY') );
         this.set( 'when_fmt_long', val.format('MM/DD/YYYY h:mm:ss a') );
         this.set( 'when_fmt_duration_ago', val.fromNow() );
         this.set( 'when_fmt_ellapsed_seconds', moment.duration( moment() - val ).as('seconds') + ' seconds' );
      }
   },

});



This works but the computed fields appear in the JSON payload to the server. If I want to avoid that, I need to overload toJSON to omit those fields from the output. Obviously, once I have several date fields, that's going to get tedious. Clearly, a generic solution that specifically addresses this issue either needed to be built or found. Fortunately, alexanderbeletsky/backbone-computedfields provides a nice extension to the model to describe computed field formats and dependencies. It then does the work to wire everything up and maintain that data:


var MomentModel = Backbone.Model.extend({

   defaults: {
      when: null
   },

   // Describe your computed fields
   computed: {

      when_fmt_short: {
          depends: ['when'],
          get: function ( fields ) {
              return moment( fields.when ).format( 'MM/DD/YYYY' );
          },
          toJSON: false
      },
   },
   
   // Wire everything up by attaching an instance of ComputedFields
   initialize: function () {
      this.computedFields = new Backbone.ComputedFields( this );
   },

});



The toJSON option determines whether the computed value will be included in the JSON payload. This solved the problem with sending it to the server. However, now the value would not be available when rendering the template in my view. While I could pass the model to the template and use the model.get() function everywhere, its not the option I prefer to use. ComputedFields provides a solution to avoid this situation by calling toJSON with an options hash that has the key computedFields set to true:


TestView = Backbone.View.extend({

   ...

   render: function() {

      // Since the default is to exclude the computed fields from the JSON payload,
      // make sure to pass an option to force them into the object for rendering in
      // the view:

      this.$el.html( this.template( this.model.toJSON({ computedFields: true }) ) );

      return this;
   },
   
   ...

});



I've posted a simple example in my sandbox that simply creates several formats and renders them to a basic template. While the computed fields are not limited to dates, they are the primary type of field I need to format. Next in line are probably number formats like currency. By using a consistent solution like Backbone.ComputedFields, these necessary formatting steps can be made easier to maintain and reusable across multiple templates while avoiding the use of the global scope moment function.

Monday, November 18, 2013

jQueryUI WaitButton Integrated with Twitter Bootstrap Styles

A few months ago, I wrote about a button widget that contained a spinner to indicate the user clicked and an action was being performed. At the time, I used the default jQuery UI styling and themes. However, now that I use Bootstrap as my base framework and cherry-pick what I need from jQuery UI, the widget lost all of its visual styling. Since the WaitButton does everything I need, I just have to figure out how to apply styles to it so it matches the button styles in Bootstrap.

I considered using addyosmani/jquery-ui-bootstrap as a solution, but wanted to start with Bootstrap styles and only add the jQuery UI classes required that further enhanced the baseline Bootstrap button. I figured this would make it a bit more resilient to changes in Bootstrap over time. The jQuery UI Button widget has options to show an icon on either the left or right side of the button text. WaitButton makes use of the icon on the left side which, in jQuery UI speak, is known as the primary icon. This content is inside the button tag so needs to be styled in a way to line up properly. .ui-button-icon* and .ui-button-text* are the set of classes involved in aligning this content, however, they can't just be copied into your CSS from the jQuery UI styles. The padding and positioning won't result in a button that matches other Bootstrap buttons. If you were to line them up, the jQuery UI buttons will be taller and wider for the same text. Additionally, Bootstrap offers several colors of buttons which require the animated GIF in the WaitButton to match. I attempted to use a transparent background but it just didn't look good so I created several GIFs (ajaxload.info) with matching backgrounds and created styles to swap the correct GIF into the button based on the btn-* class applied.

I eventually narrowed the set of styles down to these classes with the additions of the WaitButton specific classes to enable swapping the GIFs for different button colors. You can see a demo of the buttons on my sandbox and also download the CSS/GIfs required to adapt the WaitButton widget to work nicely with Bootstrap.

Monday, November 11, 2013

Using Mailgun's Event API to Poll for New Messages

If you've ever tried to write email processing logic, you know dealing with IMAP/POP and MIME are all acronyms you'd like to avoid. Having fought that battle in the past, I really did not want to worry about those details. Instead, I want to send and receive messages without worrying about the underlying mechanisms that enable it. This is where Rackspace's Mailgun solution saves the day. Now, mail can be handled using a simple REST API and their servers abstract all the details of MIME, mail protocols, etc. On top of that functionality comes a lot of other great features like mailing lists, campaign tracking, etc. However, my first goal was to tackle sending/receiving mail. Sending turned out to be quite simple, however, receiving required a little more work.

One of the main components of Mailgun are using various webhooks to notify you in real-time that something has happened. As long as you have a publicly accessible server, you can receive the event and act accordingly. However, utilizing this mechanism to accept a message is not always possible. The alternative approach requires you to look for stored events via the Events API end point, extract the message key, and then call the Messages API end point to retrieve the actual message. When polling the events, you'll need to know if you already processed a message so you know not to attempt to retrieve it again. As a result, you need to keep some state information locally to compare against while reading the events. This data only needs to be retained long enough to be outside of the maximum window that you'll use in the Events API call.

Monday, November 4, 2013

Considerations on Client-Side Javascript Caching Strategies

If you look at any library that implements a type ahead like search widget, you will inevitably see a solution for caching remote search results. Its a problem that pops up just about anywhere that you have a list of data that you'd like to reuse without making another round trip to the server to fetch. Recently, I've been working on several projects which required a variety of caching techniques. I spent some time trying to isolate the commonalities between them so I could reuse parts of the logic and avoid writing a bunch of redundant code. Below, I've tried to highlight the approach I took to solving some of these common problems.

Before anything is cached, you need to make a request to fetch data from the server to start filling that cache. Let's assume you have a text box that the user will type a search string in and, as they type, it triggers the lookup - either in the cache or on the server. Since you'd rather avoid firing multiple concurrent requests to the server while the user is typing, you'd like to employ a method of throttling the search requests. Since I already have Underscore loaded, I prefer to use as much of its functionality as possible before either writing my own solution or looking elsewhere. The library contains several handy "function" functions which essentially wrap functions with enhancements. In the case of the _.throttle() function, it takes a passed in function and wraps it with throttling logic to prevent that function from being fired except after a certain delay has occurred first (or the other way around or both - see the documentation for a full explanation):

   this.fetchData = _.throttle( function( p ) {
   
        /* if search is already in cache */
            /* return cached data set */
        /* else */
            /* $.ajax() to server */
      },
   },
   500,               // Timer in milliseconds
   { leading: false } // Only triggered on the falling edge
);