Part 1

TL;DR? Code for part 2

In part 2 of this guide, I want to be able to switch the displayed view controller when the menu option is selected. Right now, the menu is pretty useless. You can select it but only MainViewController is shown. Let’s change this.

Two more view controllers

Let’s add 2 more view controllers in storyboard. I am going to call them YellowViewController and RedViewController and change each view’s background color appropriately.

Again, don’t forget to change the Custom Class and Storyboard ID of each view controller to its respective ViewController class.

img

Update menu options

In part 1, we named our menu options Option A, B and C. To make things a bit more clear, let’s change it to Main, Red, and Green.

img

Listening to menu change

To recap, ContainerViewController holds reference to both MenuViewController and the UINavigationController that holds MainViewController. In MenuViewController, we could get a reference to UINavigationControllerand ask it to switch the displayed view controller. That would look something like this.

((self.parentViewController as! ContainerViewController).rightViewController as! UINavigationController).pushViewController(redViewController, animated: true)

There is no problem with this but it creates a tight coupling between MenuViewController and ContainerViewController. If we tried to contain MenuViewController inside another view controller, this code could break. Another way to achieve this is by sending a notification when a menu option is selected. This way, other objects can listen to those notifications and act on them.

import UIKit
class MenuViewController: UITableViewController, UITableViewDelegate {
    @IBOutlet var menuTableView: UITableView! {
        didSet{
            menuTableView.delegate = self
            menuTableView.bounces = false
        }
    }
    
    struct Notifications {
        static let MainSelected = "MainSelected"
        static let RedSelected = "RedSelected"
        static let GreenSelected = "GreenSelected"
    }
    
    override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
        let item = indexPath.item
        let center = NSNotificationCenter.defaultCenter()
        
        switch item {
        case 0:
            center.postNotification(NSNotification(name: Notifications.MainSelected, object: self))
        case 1:
            center.postNotification(NSNotification(name: Notifications.RedSelected, object: self))
        case 2:
            center.postNotification(NSNotification(name: Notifications.GreenSelected, object: self))
        default:
            println("Unrecognized menu index")
            return
        }
    }
}

tableView: didSelectRowAtIndexPath will get called when user taps on the menu option. When that happens, we send a notification with a name specific to that row. The next piece of the puzzle is to observe this notification and act on it. We want the UINavigationController to receives this notification and displays the correct view controller. In order to do this, we first need to create a custom UINavigationController. I am going to name this MainNavigationController.

In the storyboard, click on the Navigation Controller that is pointing to MainViewController. Under its Identity Inspector, change the class name to MainNavigationController.

img

import UIKit

class MainNavigationController: UINavigationController {

    private var mainSelectedObserver: NSObjectProtocol?
    private var redSelectedObserver: NSObjectProtocol?
    private var greenSelectedObserver: NSObjectProtocol?
    
    override func viewWillAppear(animated: Bool) {
        super.viewWillAppear(animated)
        addObservers()
    }
    
    override func viewWillDisappear(animated: Bool) {
        super.viewWillDisappear(animated)
        removeObservers()
    }
    
    private func addObservers() {
        let center = NSNotificationCenter.defaultCenter()
        let storyboard = UIStoryboard(name: "Main", bundle: nil)
        
        mainSelectedObserver = center.addObserverForName(MenuViewController.Notifications.MainSelected, object: nil, queue: nil) { (notification: NSNotification!) in
            let mvc = storyboard.instantiateViewControllerWithIdentifier("MainViewController") as! UIViewController
            self.setViewControllers([mvc], animated: true)
        }
        
        redSelectedObserver = center.addObserverForName(MenuViewController.Notifications.RedSelected, object: nil, queue: nil) { (notification: NSNotification!) in
            let rvc = storyboard.instantiateViewControllerWithIdentifier("RedViewController") as! UIViewController
            self.setViewControllers([rvc], animated: true)
        }
        
        greenSelectedObserver = center.addObserverForName(MenuViewController.Notifications.GreenSelected, object: nil, queue: nil) { (notification: NSNotification!) in
            let gvc = storyboard.instantiateViewControllerWithIdentifier("GreenViewController") as! UIViewController
            self.setViewControllers([gvc], animated: true)
        }
    }
    
    private func removeObservers(){
        let center = NSNotificationCenter.defaultCenter()
        
        if mainSelectedObserver !=  nil {
            center.removeObserver(mainSelectedObserver!)
        }
        if redSelectedObserver != nil {
            center.removeObserver(redSelectedObserver!)
        }
        if greenSelectedObserver != nil {
            center.removeObserver(greenSelectedObserver!)
        }
    }

}

That’s it!

You now should be able to select the menu and see the displayed view controller change. The code for part 2 can be found here

TL;DR? Code for part 1

Architecture

Before jumping into the code, let’s think about how we are going to structure our views and controllers to make this happen. In this guide, I am going to use 3 view controllers. They are:

  • MenuViewController : This will be a subclass of UITableViewController. Its job is to display the available menu options.

  • MainViewController : This will be a normal UIViewController that will be switched in/out depending on what is selected on the menu. I am going to also embed this view controller inside UINavigationController.

  • ContainerViewController : This will be the controller that holds both MenuViewController and MainViewController

The ContainerViewController will be the one handling the swipe left and right gesture. It will have 2 IBAction functions that will animate the menu view.

Let’s start coding. Open XCode and create a Single View Application project.

ContainerViewController

Our entry point for this app is going to be the ContainerViewController. This view controller will hold references to the menu and the currently displayed view controller. When user swipes left/right, this view controller will animate the displaying and hiding of the menu.

In viewDidLoad, take a look at how MenuViewController and the navigation controller of MainViewController get loaded and assigned to leftViewController and rightViewController respectively.

Take not of the @IBAction functions. We will need to attach them in the storyboard later.

import UIKit

class ContainerViewController: UIViewController {
    var leftViewController: UIViewController? {
        willSet{
            if self.leftViewController != nil {
                if self.leftViewController!.view != nil {
                    self.leftViewController!.view!.removeFromSuperview()
                }
                self.leftViewController!.removeFromParentViewController()
            }
        }
        
        didSet{
            
            self.view!.addSubview(self.leftViewController!.view)
            self.addChildViewController(self.leftViewController!)
        }
    }
    
    var rightViewController: UIViewController? {
        willSet {
            if self.rightViewController != nil {
                if self.rightViewController!.view != nil {
                    self.rightViewController!.view!.removeFromSuperview()
                }
                self.rightViewController!.removeFromParentViewController()
            }
        }
        
        didSet{
            
            self.view!.addSubview(self.rightViewController!.view)
            self.addChildViewController(self.rightViewController!)
        }
    }
    
    var menuShown: Bool = false
    
    @IBAction func swipeRight(sender: UISwipeGestureRecognizer) {
        showMenu()
        
    }
    @IBAction func swipeLeft(sender: UISwipeGestureRecognizer) {
        hideMenu()
    }
    
    func showMenu() {
        UIView.animateWithDuration(0.3, animations: {
            self.rightViewController!.view.frame = CGRect(x: self.view.frame.origin.x + 235, y: self.view.frame.origin.y, width: self.view.frame.width, height: self.view.frame.height)
            }, completion: { (Bool) -> Void in
                self.menuShown = true
        })
    }
    
    func hideMenu() {
        UIView.animateWithDuration(0.3, animations: {
            self.rightViewController!.view.frame = CGRect(x: 0, y: self.view.frame.origin.y, width: self.view.frame.width, height: self.view.frame.height)
            }, completion: { (Bool) -> Void in
                self.menuShown = false
        })
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let storyboard = UIStoryboard(name: "Main", bundle: nil)
        let mainNavigationController: UINavigationController = storyboard.instantiateViewControllerWithIdentifier("MainNavigationController") as! UINavigationController
        let menuViewController: MenuViewController = storyboard.instantiateViewControllerWithIdentifier("MenuViewController")as! MenuViewController
        
        self.leftViewController = menuViewController
        self.rightViewController = mainNavigationController
    }
}

Storyboarding

ContainerViewController

The ContainerViewController will just be an empty UIViewController. Drag UIViewController in Main.storyboard.

For hiding and showing menu, add Swipe Gesture Recognizer for each left and right swipe (you can change the direction in the Attribute Inspector) and set the sent action to the appropriate @IBAction in ContainerViewController.

img

Under Identity Inspector, set the Custom Class of this view controller to ContainerViewController.

img

Our menu will just be a custom UITableViewController with a finite number of rows. You can achieve this by setting the table view’s content as Static Cells. You can find this setting under the Table View’s Attributes Inspector.

img

For this guide, I am going to have 3 menu items. To do this, select Table View Section under Table View and, under its Attributes Inspector, set the Rows value to 3. Once you have done this, you can add UILabel inside the cell’s content view.

img

Set the Custom Class and Storyboard ID of this view controller to MenuViewController. We have to set the Storyboard ID because we want to be able to load a reference to this view controller from storyboard (look at ContainerViewController’s viewDidLoad).

img

MainViewController

For this, just drag and drop a new View Controller and set its Custom Class and Storyboard ID to MainViewController

Part 1 Done

That’s it. You now should be able to build and run the app. The menu should slide in/out when you swipe. You can checkout the code for part 1 here.

Go To Part 2

Suppose you have a website on example.com and you want to create a blog that points to blog.example.com. How do you do this? Well, assuming that you are using NGINX and using Linode for hosting, I am going to teach you just that.

Your NGINX Site Config

For me this is located inside, /etc/nginx/sites-available directory. I name each site config using its domain name. So, for our use case, that directory would contain two files, example.com and blog.example.com.

example.com site config may look something like:

server {
    listen 80;
    server_name example.com www.example.com;
    root /var/www/example.com;
}

So, what about your blog.example.com site config. That would look something like:

server {
    listen 80;
    server_name blog.example.com;
    root /var/www/blog.example.com;
}

Requests that starts with blog.example.com will be served with assets under /var/www/blog.example.com.

I hope that’s pretty straight forward and obvious. But, doing this alone, will not give you what you want.

Adding A Record

This is the one thing that I forgot to do and I spent a while trying to figure out why the subdomain did not work.

Login to your Linode and select the server that’s hosting your website. Click on the DNS Manager tab. In there, assuming that you already set up the parent domain web site, you should have an entry for your website which you are creating a new subdomain for. Click Edit for that domain entry.

You should now see a familiar page that lists all DNS records. Find the section that lists A/AAA Records and click Add a new A record.

You should now see a form with 2 text fields (Hostname and IP Address) and 1 select input. For the hostname, enter blog.example.com and, for the IP address, enter the server’s IP address. Leave the select input alone. Click Save Changes and you are good to go.

Sorry for not having pictures. Feel free to send me e-mail/leave comment if you have questions though.

When you are using a UI component from libraries like JQuery UI or Zurb Foundation, in order for that component to work properly, you need to enable it after DOM is ready.

An example of this is, in Zurb Foundation, the following needs to be called in order for your drop-down menu to function:

$(document).foundation('dropdown', 'reflow');

In a non-SPA world, this can be achieved by doing:

$(function(){
  //Gets called when DOM is ready. Easy Peazy!
  $(document).foundation('dropdown', 'reflow');
})

So how do we achieve the same thing in Ember SPA?

TL;DR

You have to create a view for your template!!! Ember (and/or Ember-cli), by convention, does not require you to have a view to render a template. UsersRoute, by default, will render users.hbs without needing UsersView. But, if you want to execute a JS after the template is rendered, so far, the only way that I’ve found is to create a UsersView.

This is how your UsersView would look like:

import Ember from 'ember';

var UsersView = Ember.View.extend({
  templateName: 'index', //we want to render 'users.hbs'

  didInsertElement: function(){ //Duh, obviously this is going to be called after element is inserted
    "use strict";
    $(document).foundation();
  }
});

export default UsersView;

TL;DR done

DOH!

I really should have known this! Especially after writing the last blog post. I found out about this the hard way after trying to run that code in:

  • An initializer. Obviously this is not going to work. This gets called when the app starts and the template would not be in DOM when this initializer gets called.

  • Route’s didTransition callback. Close but still no-go. The template won’t be in DOM when the function is called.

  • Ember.run.scheduleOnce('afterRender', this, function(){ /* Do stuff here */}). I tried this. I really think this should have worked. Still not to sure why it didn’t. If you know why, please let me know!

Thank you for reading. Hopefully, I saved you some time and agony.

Disclaimer: I use ember-cli for my current project and I will be using some ES6 syntax in this post.

I am going to share how I created a re-usable date picker input field using JQuery UI Date picker and Ember View.

1. Create the custom Ember.View

// File path: ./app/views/date-field.js

import Ember from 'ember';

var DateFieldView = Ember.View.extend({
  tagName: 'input',
  classNames: ['date-picker'],
  attributeBindings: ['type', 'model', 'property'],
  type: 'text',
  model: null,
  property: '',

  didInsertElement: function(){
    "use strict";
    $(this.element).datepicker();
  },

  change: function(e){
    "use strict";
    var property = this.get('property');
    var model = this.get('model');
    var newVal = $(e.target).val();
    model.set(property, newVal);
  }
});

export default DateFieldView;

This custom view takes 2 required parameters, model and property. The model parameter determines which object this view should modify when the value gets changed. The property parameter determines which property of the object this view should modify when the value gets modified. The change function gets called when the value is modified. It grabs the value of the field and set it to the model’s property.

The didInsertElement function is called when the element is inserted. For our case, we want to make sure that JQuery’s date picker is enabled for this element.

2. Use it in your view

<div class="large-3 left column">
  {{view 'date-field' model=model property='dueDate'}}
</div>

Hopefully that was pretty straight forward. Thanks for reading :)