Category Archives: Coding

Django, Backbone, Handlebars

My whole programming career, I’ve defined myself as a back-end programmer. I know some javascript, but I feared CSS and the seemingly nit-pickyness of front-end coding.

Presently, I’m  building my own site for PinTheParty, and I *really* don’t want to bring another developer into the mix. I need to figure out how to do this on my own. I also need to redefine myself as a full-stack developer.

I’ve decided to use Python/Django with Backbone.js and Handlebars. There are many blog posts about bringing these and other frameworks together. But nothing exactly the way I wanted to do it. So I’m documenting my setup here.

      • First: Build the HTML page, including a template to use with Handlebars
        The venue_list div is where we will inject our rendered html from a Handlebars template. I’m also showing the js includes at the bottom. I’m using a library called ‘require’ to help organize all the js dependencies. This way, I don’t need to include all the js in the html, I can refer to it in each html’s supporting js file.
      • <div class="col-md-7">
             <div class="row search-results">
                 <div class="entry-searching-header">Searching "bake cupcakes"</div>
                 <div class="entry-header">25 results</div>
                 <div id="venue_list">
        
                 </div>
             </div>
         </div>
        ....
        <script data-main="/static/scripts/main" src="/static/scripts/require.js"></script>
        <script src="/static/scripts/venues.js"></script>
      • Second: Build the template contents using Handlebars tags in mark injection points.
        {{#each venues}}
        <div class="entry">
          <div class="row">
            <div class="col-md-6">
              <div class="entry-title"><a href="/venue/{{slug}}">{{name}}</a></div>
              </div>
            <div class="col-md-3 entry-cost">{{cost}}</div>
            <div class="col-md-3">
              <img alt="" src="/static/imgs/gograph_blue_ribbon.jpg" width="12px" />
            </div>
            <div class="row">
              <div class="col-md-12">
              <div class="entry-category">{{categories}}</div>
              <div class="entry-quote">{{quote}}</div>
            </div>
        </div>
        {{/each}}
      • Third: Build the supporting Backbone Model, Collections and View.
        I used one file to contain the Model, Collections and View to keep things simple. Notice, this is also where I use the require library at the top to help include required js dependencies, such as Backbone!  There are a couple choices I made.

        • I’m using an api to deliver the json
        • I fetch the data for the collection when it is first initialized. Because this is an asynchronous call, I need to make sure the template is injected when the data arrives. This is accomplished by setting “reset : true” in the call to collection.fetch and binding the render function call to the reset event. (By default the fetch will call “add” for each item in the json array)
        • When a collection receives json data and populates the associated models it expects an array of items. This is what I’m returning from the /api/vi/venues call. However the Handlebars syntax I’m using, {{#each venues}}, expects a parent element. So I add “venues:” when I pass the json to the template
        • There are two require blocks at the beginning of the file. The inner, nested require block is to include all the dependencies for this js file. The outer, require block is to load min.’s — the configuration file for require.js . Require.js recommends you use ONE main.js file to set the baseUrl as well as include js libraries that are used across the application. I don’t know if this is the best solution (nested require statements) but due to the way main.js is loaded (asynchronously using the data-main script attribute), I needed to make sure main.js is loaded before referring to its elements (i.e. backbone, underscore..)
require(['main'], function() {
	require(['jquery',
	        'underscore',
	        'backbone',
	        'handlebars',
	        'libs/text!../templates/parts/venue_list.html'],function($,_,Backbone,Handlebars,ListTemplate){

	    var Venue = Backbone.Model.extend({
	        defaults: {
	            name: 'My Favorite Place',
	            slug: 'my-favorite-place',
	            cost: '$$$',
	            quote:'Good for all ages with extremely helpful and competent staff!'
	        }
	    });

	    var VenueList = Backbone.Collection.extend({
	        model: Venue,
	        url: '/api/v1/venues',

	        initialize: function(){
	            this.fetch({reset:true,
		              success: function(collection, response) {
			          }
			    });
	         }
	    });

	   var venues = new VenueList;

	    var VenueListView = Backbone.View.extend({
	        el: '#venue_list',
	        // The collection will be kept here
			collection: null,

	        initialize: function(options) {
		        this.collection = options.collection;
			    // Ensure our methods keep the `this` reference to the view itself
			    _.bindAll(this, 'render');
			   this.collection.bind('reset', this.render);
			  },

	        render: function() {
		       var template = Handlebars.compile(ListTemplate);
		       var html = template({venues:this.collection.toJSON()});
		       this.$el.html(html);
	           return this;
	        }

	    });
	   	var myList = new VenueListView({
		      collection: venues
		});
	});
});
Advertisements

Table view on top of horizontal scroll view

I created an app with a UITableView main screen. There are about 12 rows in my table each used to describe a particular characteristic of an item for sale, including the ability to upload photos of the item. Simply stated, the user can tap each row to be brought to a detail screen. After entering their selections the user returns to the main table view.

Image

To add photos to an item, you click on the row labeled “More Photos” and are brought to a photo screen like this:

Image

After initial development was complete we decided it would improve usability if the photo details were pulled out from their detail screen to the top level main screen. I need to split the screen into two views: the main table view which scrolls top to bottom, and a persistent horizontal scroll area at the bottom. The main table view will scroll “under” the image scroll view at the bottom. I tried a couple ways to do this which didn’t work:

  • Place a UIScrollView on top of the UITableView so it will cover the bottom part of the screen. Not only did my scroll view not even show up in the simulator (probably hidden beneath the table), I’m certain the bottom of the table would never get a chance to scroll above the horizontal scroll view.
  • Change the height of the UITableViewController tableView in the viewDidLoad event. This did nothing for me. Not sure if the table was already drawn, so perhaps I could not affect the height.
  • Create a ViewController in the Storyboard, place two ContainerView objects on it which automatically create segues to two related view controllers. This did not run in my iPhone 5 Simulator because it complains these types of segues are not available in 5.1 and before. (arg)

SO, lets create my own in the code!

After reading this fantastic tutorial on Containing ViewControllers, I decided to create a Container ViewController which would have two child view controllers (not just child views). I call the containing VC “MyContainerViewController”. In my header file I have two attributes for the child VCs. One for the tableview, “ListItemViewController” and one for adding photos, “MorePhotosViewController”.


@interface MyContainerViewController : UIViewController{
//NSArray *_subViewControllers;
ListItemViewController *listItemViewController;
MorePhotosViewController *morePhotosViewController;
}

@property (nonatomic, strong) ListItemViewController *listItemViewController;
@property (nonatomic, strong) MorePhotosViewController *morePhotosViewController;

Then in viewDidLoad of my containing view controller, I instantiate and add my two ViewControllers as children. Also, I add each view of the viewControllers as subviews to the ContainingViewController. When I instantiate the tableview, I change the height to allow for the new horizontal scroll view which will set below it.



listItemViewController = [[ListItemViewController alloc] init];

//Grab the dimensions of the container view.
CGRect myframe = [self.view frame];

//Set the tableview to be 190 pixels shorter than the full view. 
//Also Leave a little room at top for the nav bar
[listItemViewController.tableView setFrame:CGRectMake(myframe.origin.x,
 myframe.origin.y-20,
 myframe.size.width,
 myframe.size.height - 190 )];

//ScrollView is created and sized within the child VC's viewDidLoad method
morePhotosViewController = [[MorePhotosViewController alloc] init];

// add as child VC
[self addChildViewController:listItemViewController];

// add it to container view
[self.view addSubview:listItemViewController.view];

// add as child VC
[self addChildViewController:morePhotosViewController];

// add it to container view
[self.view addSubview:morePhotosViewController.view];

In the viewDidLoad method of my horizontal scroll view, MorePhotosViewContoller, I create a scrollview, size it and add it as a subview



CGRect myframe = [self.view frame];
    UIScrollView *imageScrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(myframe.origin.x,
                                                                                   myframe.size.height - 190,
                                                                                   myframe.size.width,
                                                                                   190 )];

    imageScrollView.contentSize = CGSizeMake(myframe.size.width*2, 190);
    imageScrollView.showsHorizontalScrollIndicator = YES;
    //  imageScrollView.backgroundColor = [UIColor grayColor];
    [self.view addSubview:imageScrollView];

I also add a bunch of image placeholders for the user to click on to “add a photo”.

The last step is to replace my original tableview in the navigation hierarchy with my containing VC. So I go to the storyboard and do just that. I make MyContainerViewController the rootViewController for my NavigationController. And here is the result!

horizontalScroll

Looks great, but there is one problem. All of the table cells that fall below the photo bar at the bottom do not respond to taps once they scroll into view! The way I solved this is to grab all the tap events for the table view through a gesture recognizer, determine which row the user tapped and trigger the selection event myself. A little hacky? Not too bad, I think.


- (void)tapped:(UIGestureRecognizer *)gestureRecognizer
{
    CGPoint point = [gestureRecognizer locationInView:self.tableView];

    CGFloat theRowHeight = [self.tableView rowHeight];

    CGRect btnCurrentFrame = CGRectMake(self.btnSave.frame.origin.x, (self.btnSave.frame.origin.y + self.tableView.contentOffset.y),self.btnSave.frame.size.width,self.btnSave.frame.size.height);

    CGFloat theRowNum = point.y / theRowHeight;
    float roundedRowNum = ceilf(theRowNum);
        NSIndexPath *indexPath = [NSIndexPath indexPathForRow:(roundedRowNum-1) inSection:0];

    [self.tableView selectRowAtIndexPath:indexPath animated:NO scrollPosition:UITableViewScrollPositionNone];
    [self tableView:self.tableView didSelectRowAtIndexPath:indexPath];
}

Front end coding for a back end girl

For some reason I’ve always steered clear of front end coding. I’ve had moments in my career where I’ve been a javascript guru, but then the standards and versions change and I’m just a know-nothing again. At the same time, I find great gratification from producing elegant GUIs. The instant gratification of changing a color, or triggering an action, can be so much fun.

I was finally persuaded to take a course on HTML5/CSS3 at Noble Desktop with a friend of mine who was attending. First off, let me tell you, this is a GREAT school. The instructor really knew her stuff. She taught the material clearly and at a nice pace and she was also able to answer any odd question you threw her way. She also had personal anecdotes about browser compatibility and nuances of working in a company that prohibits upgrading to latest browser versions. I was so happy to know she had been in the trenches and was not just an academic.

It was a two day course focusing on building a webpage using HTML5 elements such as video, and audio as well as new CSS3 modules such as transitions, multiple backgrounds, borders, shadows, etc. All this was really fun and fulfilled my “immediate gratification” quotient. But what I found most enjoyable and impressive is how much they focused on cross browser compatibility and gradual degradation. I guess this comes with the trade..to be a really good CSS coder, you have to know cross browser compatibility WELL.  And thus, that was the part of front-end coding that I was not looking forward to. However, HTML5/CSS3 and many open source libraries make it sooooo easy. Have you heard of Modernizr? It is a feature detection library for CSS3. So instead of asking the client browser what VERSION it is, the code can simply ask the client browser which FEATURES it supports. Then you can write logic to implement the ‘x’ feature if supported and provide a work-around, or perhaps even nothing, if its not supported. CSS and its community has come a long way since the last time I took a look at it. This class made me want to go build my own website soup to nuts….front end to back end. So fun not to be a know-nothing for the time being.