How to do toggle functions in Backbone.js the right way

Recently a co-worker was asking me how best to implement a piece of toggle functionality in to a Backbone.js view. He was trying to replicate the usual jQuery toggle pattern within his backbone app but was getting confused and having some troubles accessing it from other views. This confusion comes from the fact that backbone suggests you create all of the view’s events using the events hash.

I’m writing this blog post because I actually had the exact same issue when I first started working with backbone so I feel it is a common issue and hopefully if you are reading this post I can shed some light on the subject for you.

Toggle functionality can be common in UI designs and usually is used to implement some kind of ability to turn something on and off or to disable then enable a piece of the UI.

There is an answer for this question on StackOverflow but personally I don’t really like the answer and would like to show you a more usable and dynamic way of creating some toggle functionality within your backbone views.

I prefer my approach below because I can easily allow other views access to my methods via a global events dispatcher or simply check the state of the object from another view and maybe display a message to the user within another view.

The ability to turn toggle functionality on and off in different places is really neat. This can easily crop up for instance when a client wants to move the button from one place to another and you find your self struggling with the move. Because we have the toggle state included as a property of the object we can easily check the current state of an element if need be, it will allow for much more complex use cases.

var View = Backbone.View.extend({
  events: {
    'click': 'toggleContent'
  },
  showmeState: true,
  toggleContent: function(){
    if (this.showmeState === false) {
      this.showText();
    } else {
      this.hideText();
    }
  },
  hideText: function() {
    this.$el.find('p').hide();
    this.showmeState = false;
  },
  showText: function() {
    this.$el.find('p').show();
    this.showmeState = true;
  }
});

Another use case for the above code would be for an Auto Sorting and Render of a collection in a live data environment.

var View = Backbone.View.extend({
  autoSortTimer: "",
  events: {
    'click': 'autoSort'
  },
  autoSorting: false,
  autoSort: function() {
    if(!this.autoSorting) {
      this.startAutoSort();
    } else {
      this.stopAutoSort();
    }
  },
  startAutoSort: function() {
    this.autoSorting = true;
    this.autoSortTimer = setInterval(function() {
      Dispatcher.trigger('resort');
    }, 1000);
    this.$el.find('#auto-sort-label').html('Auto Sort Columns - On');
  },
  stopAutoSort: function() {
    this.autoSorting = false;
    var autoSortTimer = this.autoSortTimer;
    clearInterval(autoSortTimer);
    this.autoSortTimer = "";
    this.$el.find('#auto-sort-label').html('Auto Sort Columns - Off');
  }
});

Gulp vs Grunt

Gulp and Grunt are JavaScript task runners, I will assume you already have an understanding of what they do and your just looking for a reason to use one or the other.

In all honesty I haven’t spent more than a week or so in terms of man hours working with either Grunt or Gulp. But to me Gulp feels like the better option.

Why Gulp?

Switching to Gulp from Grunt it instantly felt faster, now that is no fair test… so a little bit of a Google search and I can confirm that yes in fact Gulp is the faster option.

The Key Difference

From my point of view the key difference between the two is the syntax in the task runner file.

Grunt uses JSON where as Gulp uses JavaScript.

I found Gulp a little easier to navigate and augment, it feels easier to customize and the ability to bind path names to variables was more familiar.

Reasons to use Grunt

Grunt has a longer History, more plugins and generally more support at the moment.

Before you choose Gulp check the plugin support for the tasks you need to run, it may be that some of the functionality you need currently only exists in a Grunt plugin and then using Gulp will not be possible.

Conclusion

Every article I have read seems to agree, Gulp is the task runner of choice among the cool kids. Gulp just feels right! At this point in time I have upgraded my task runner to Gulp, unless I have some major issues or problems with Gulp I don’t see any reason to use Grunt.

Backbone.js and Require.js Boilerplate

It’s painstakingly slow to start projects in Backbone using Require. I have created a simple boilerplate to save me some time when I need to start a new Backbone project.

The app contains a single model, a single collection and a single view. It also has support for the Require.js text library for ajaxing templates into the app.

The current folder structure is as follows:

├── css
│   └── base.css
├── js
│   ├── app
│   │   ├── tmpl
│   │   │   └── template.html
│   │   ├── collection.js
│   │   ├── model.js
│   │   └── view.js
│   ├── libs
│   │   ├── backbone-min.js
│   │   ├── jquery-2.0.3.min.js
│   │   ├── text.js
│   │   └── underscore-min.js
│   ├── main.js
│   └── require.js
└── index.html

It’s a bare bones approach and it’s hosted on GitHub, feel free to download it and maybe even contribute to it.

Adding a second scroll bar to jScrollPane

This week I have been writing some code to create a scroll-able container with two scroll bars, one at the top of the container and one at the bottom. This is for a live streaming stock market watch list app that I am currently working on.

Using jScrollPane for custom scroll bars makes this is a fairly easy piece of UI to create.

jScrollPane initialises and we listen for the 'jsp-initialised' event, we then start to create the second scroll bar by using the jQuery .clone() method and then assign some additional style and ID attributes. JQuery clone also clones the events which the original scroll bar had so instantly it works and we simply need to create some logic for syncing the two scroll bars together.

Once we have our second scroll bar, we can then attach some jScrollPane events so that they scroll together.

Let’s look at a working example

The following code is hosted on codepen.io.

Now let’s look at the code behind this example

First of all we need to get some CSS and JavaScript files. Then we simply create a container and add some jScrollPane classes to it.

<link type="text/css" href="http://jscrollpane.kelvinluck.com/style/jquery.jscrollpane.css" rel="stylesheet" media="all" />
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/2.0.3/jquery.min.js"/>
<script src="http://cdnjs.cloudflare.com/ajax/libs/jScrollPane/2.0.14/jquery.jscrollpane.min.js"/>

<div class="scroll-pane horizontal-only">
  
  <p>The path of the righteous man is beset on all sides by the iniquities of the selfish and the tyranny of evil men. Blessed is he who, in the name of charity and good will, shepherds the weak through the valley of darkness, for he is truly his brother's keeper and the finder of lost children.</p>

  <p>And I will strike down upon thee with great vengeance and furious anger those who would attempt to poison and destroy My brothers. And you will know My name is the Lord when I lay My vengeance upon thee.</p>

</div>

Some additional CSS to make the <P> tags wider than their parent container. This is so the scroll pane is needed to scroll the content.

body {
  font-family: Arial;
}

body .scroll-pane {
  height: 150px;
  width: 800px;
  background: white;
}

body .scroll-pane p {
  width: 1000px;
  margin: 0 0 10px 0;
}

body .jspHorizontalBar {
  background: #fff;
}

Above we have a standard setup for a single scroll bar container now we need to duplicate the scroll bar and attach the custom functionality. The jScrollPane events API is where we can find information on other jScrollPane events. For now we simply need to attach some code to the 'jsp-initialised' and the 'jsp-scroll-x' events.

$(document).ready(function() {

  var $bottom_bar,
      $top_bar;
 
  //Listen for the initalization event.
  $('.scroll-pane').bind('jsp-initialised', function(event) {
  
      //Locate the bottom scroller and clone it, with events
      //add ID attibute to both the top and bottom bars.
      $('.jspHorizontalBar')
      .attr('id', 'jspHorizontalBarBottom')
      .clone(true, true)
      .attr('id', 'jspHorizontalBarTop')
      .css({'position':'relative'})
      .insertBefore('.scroll-pane');
    
      $bottom_bar = $('div#jspHorizontalBarBottom').find('.jspDrag');
      $top_bar = $('div#jspHorizontalBarTop').find('.jspDrag');

  })
  //Listen for scroll events on the x axis.
  .bind('jsp-scroll-x', function(event, scrollPositionX, isAtLeft, isAtRight) {
    
      //Get the position of the bottom bar x axis and duplicate to the top bar.
      if (typeof $bottom_bar != 'undefined') {
        $top_bar.css({'left':$bottom_bar.position().left + 'px'});
      }

      //Add and remove classes to the arrow buttons.
      $('.jspArrow').removeClass('jspDisabled');

      if (isAtRight) {
        $('.jspArrowRight').addClass('jspDisabled');
      }

      if (isAtLeft) {
        $('.jspArrowLeft').addClass('jspDisabled');
      }

  })
  //Init the jScrollPane with Arrows
  .jScrollPane({

    showArrows: true

  });

});

If you have any questions about this blog post or any other please feel free to contact me via twitter.

How to use node.js and npm behind a company firewall

This morning at work I tried to get YUIDoc up and running using the standard node.js npm install approach. At work we are behind a proxy which means you have to manually edit the node.js config.

The Error

If you get an error similar to this you’re probably being blocked by the company firewall.

npm ERR! network connect ETIMEDOUT
npm ERR! network This is most likely not a problem with npm itself
npm ERR! network and is related to network connectivity.
npm ERR! network In most cases you are behind a proxy or have bad network settings.
npm ERR! network
npm ERR! network If you are behind a proxy, please make sure that the
npm ERR! network 'proxy' config is set properly.  See: 'npm help config'
npm ERR! System Windows_NT 6.2.9200
npm ERR! command "C:\\Program Files\\nodejs\\\\node.exe" "C:\\Program Files\\nodejs\\node_modules\\npm\\bin\\npm-cli.js" "-g" "install" "yuidocjs"
npm ERR! cwd C:\Users\mfasani\Documents
npm ERR! node -v v0.10.21
npm ERR! npm -v 1.3.11
npm ERR! syscall connect
npm ERR! code ETIMEDOUT
npm ERR! errno ETIMEDOUT
npm ERR!
npm ERR! Additional logging details can be found in:
npm ERR!     C:\Users\mfasani\Documents\npm-debug.log
npm ERR! not ok code 0

The Fix

It’s easy to fix the above problem assuming it’s your company’s firewall causing the issue. Speak to the network team and find out the details of your work's proxy server. Then edit the node.js config as follows:

npm config set proxy http://proxy-server-address:8080
npm config set https-proxy http://proxy-server-address:8080

Now you should be able to continue using the npm to install your packages as normal.

Debugging on the iPad, iPhone or iTouch

I’ve been working on some responsive designs recently for the iPad. Sometimes debugging on mobile devices or tablets can feel almost impossible. Luckily with the iPad you can debug remotely fairly easily.

Remote debugging for the iPad, iPhone or iTouch

There are plenty of articles and forum posts on how to connect your device to your Mac and remote debug the DOM. Unfortunately it’s not quite as easy at it looks. Many people including myself have issues with the Safari DOM inspector not working correctly, for example not fully loading CSS or HTML. This will just add to your frustrations. I have also seen people having troubles with the JavaScript debug console. It’s a classic case of two steps toward and one step back.

WebKit nightly builds to the rescue!

A post on Stack Overflow suggested debugging with the WebKit Nightly Builds browser instead as the best solution to the problem. I simply downloaded the Nightly Builds browser and from there I was able to access the remote DOM inspector in the same way without any issues.

How to?

This will only work with an Apple Mac and either and iPhone, iPad or iTouch, for best results you should upgrade to the latest OS on both devices.

Step 1:

You will need to download WebKit Nightly Builds and install it on your Apple Mac.

Step 2:

Connect your iPhone, iPad or iTouch to your Apple Mac using a USB cable.

Step 3:

Open up the WebKit Nightly Builds browser and go to “Safari > Preferences > Advanced” and check the “Show Develop menu in menu bar” checkbox.

Step 4:

On your Mobile Device go to “Settings > Safari > Advanced” and turn on “Web Inspector”.

Step 5:

In the WebKit Nightly browser go to “Develop > iPad” and from there you can access the DOM inspector (If your using an iPhone or iTouch, then it will say that device instead of the iPad).

Debug to your hearts content

This actually really speeds up the debugging and development process and once your set up it becomes super quick to test, view and fix code for any Apple device.

A Simple Backbone WordPress Example

I’ve been working on this blog now for a little under two weeks and I’ve started to build out the front end using Backbone.

WordPress JSON API

The first thing I needed was the blog content being returned via JSON so my backbone app could easily consume the data.

Plugins to the rescue, turns out some one has already done a pretty good job at creating a WordPress JSON API, I installed it and it seems to work perfectly.

Creating the backbone Front End

I’ve tried to keep this example as simple as possible. We use a model, a collection and two views.

The model is super simple:

var PostItem = Backbone.Model.extend({});

The collection contains a single API end point and a function to iterate over the data so we can push that data into the models.

var PostList = Backbone.Collection.extend({
 
  model: PostItem,
 
  url: 'http://blog.michaelfasani.com/api/get_posts/',
 
  parse: function (data) {
    var parsedData = [];
 
    //This is all the post data returned by the API call above.
    $(data.posts).each(function () {
      var id = this.id,
          type = this.type,
          slug = this.slug,
          url = this.url,
          status = this.status,
          title = this.title,
          title_plain = this.title_plain,
          content = this.content,
          excerpt = this.excerpt,
          date = this.date,
          modified = this.modified,
          categories = this.categories,
          tags = this.tags,
          author = this.author,
          comments = this.comments,
          attachments = this.attachments,
          comment_count = this.comment_count,
          comment_status = this.comment_status,
          custom_fields = this.custom_fields;
 
      parsedData.push({
        id: id,
        type: type,
        slug: slug,
        url: url,
        status: status,
        title: title,
        title_plain: title_plain,
        content: content,
        excerpt: excerpt,
        date: date,
        modified: modified,
        categories: categories,
        tags: tags,
        author: author,
        comments: comments,
        attachments: attachments,
        comment_count: comment_count,
        comment_status: comment_status,
        custom_fields: custom_fields
      });
    });
 
    return parsedData;
  }
 
});

Our first view is a view to display a single model:

var PostSingleView = Backbone.View.extend({
 
  tagName: 'li',
  
  className: 'single-post',
 
  template: _.template($('#single-post').html()),
 
  render: function() {
    this.$el.html(this.template(this.model));
    return this;
  }
});

Our second view is a list view which will display all of the single model views:

var PostListView = Backbone.View.extend({
 
  el: '#post-list',
	
  initialize: function() {
    this.listenTo(this.collection, 'sync', this.render);
    this.collection.fetch();
  },
 
  render: function() {
    this.$el.html('');
    this.collection.each(this.addSinglePost, this);
    return this;
  },
 
  addSinglePost: function(singlePost) {
    var view = new PostSingleView({
      model: singlePost.attributes
    });
  this.$el.append(view.render().el);
  }
});

I have put together a simple CSS style sheet and sample HTML page which contains my underscore templates and some containers for my views to work with.

All of this code can be downloaded and viewed via a GitHub Gist.

Michael, you fool!

Ok so in my last post I made some very bold statements, I was wrong. In the last week I have found myself wanting to do things that I simply can’t do with ghost.

Ghost is cool, but it’s very new…

I want to be able to blog on my travels to and from the office and the current mobile/tablet support for Ghost is not a great experience, I miss the WordPress app for my iPhone and iPad.

I want to have some static pages, this is currently not supported.

I am moving my blog back to WordPress.

It reminds me of a statement made by Terrence McKenna who said the following:

History is ending, because the dominator culture has led the human species into a blind alley. And as the inevitable chaostrophe approaches, people look for metaphors and answers. Every time a culture gets into trouble, it casts itself back into the past looking for the last sane moment it ever knew. And the last sane moment we ever knew was on the plains of Africa, 15,000 years ago, rocked in cradle of the great horned mushroom goddess before history. Before standing armies, before slavery and property, before warfare and phonetic alphabets and monotheism. Before, before, before. And this is where the future is taking us. Because the secret faith of the 20th century is not modernism. The secret faith of the 20th century is nostalgia for the archaic, nostalgia for the Paleolithic, and that gives us body piercing, abstract expressionism, surrealism, jazz, rock and roll, and Catastrophe Theory. The 20th century mind is nostalgic for the paradise that once existed on the mushroom-dotted plains of Africa, where the plant-human symbiosis occurred that pulled us out of the animal body and into the tool-using, culture-making, imagination-exploring creature that we are.

I’m scared to continue down my new path, so I am running back to what I know best.

Hello world!

Welcome to my shiny new blog. I am a front-end web developer from London and this is my first post using Ghost.

Why am I starting a blog?

It’s the chance to try something new, a playground to learn and document my findings. A place to showcase my talent as a web developer and a place on the web to call home. It may even help some people along the way (Hopefully).

Why I didn’t want to use WordPress!

I could just hit the ground running and start blogging. With WordPress it would be way too easy for me to use all of the existing amazing plugins and themes that have already been created to quickly build a really awesome blog. For most people I guess that’s the main advantage of using WordPress.

I really wanted to run a blog that I would be proud of as a developer, a place to really call home and I just didn’t feel that WordPress would be the right path for me to go down.

Don’t get me wrong I love WordPress and have built many websites using it in the past, but for my own personal development blog I just really wanted something that would take a little more time and effort to get comfortable with.

Ghost – It’s the future!

Ghost is a brand new blogging engine which started development just 6 months ago when John O’Nolan started a fund-raiser on kickstarter. The project was backed by 5,236 people and raised £196,362.

I am choosing Ghost simply because I think it’s cool.

It’s written almost entirely in JavaScript and I am looking forward to developing the platform, themes and plugins which will all go back into the community. The only real way to be able to do that is to use the platform for my own personal blogging adventures.

How did I get started?

Simples! I visited Host Ghost and they hooked me up as a Beta Tester!

Any Questions?

You can find me on twitter if you want to get in touch.