Routes with parameters

Okay, we’ve set up multiple routes but we still need to look at how we can include parameters within them. This is important to allow a level of dynamism within our contacts manager. For example, we’re going to be using them to view a specific contact by referencing an ID number or index.

Adding a parameter is easy; we just need to add a placeholder in. This is done with a colon followed by the name of the parameter we wish to create. Let’s take a look at the route we’re going to make to view our contact. Once more, we can chain this onto our existing routes:

.when('contact/:id', {
    controller: 'contactCtl',
      templateUrl: 'assets/partials/contact.html'
});

We can add as many parameters as required, and it’s easy to pull these out in our controller. It’s just a case of injecting a service into the controller and we’ll have access to all route parameters as objects:

.controller('contactCtl', function($scope, $routeParams){
    console.log($routeParams);
});

If you navigate to localhost:8000/#/contact/1 and open up your console, you’ll see the route parameters logged as a JS object:

Routes with parameters

That means we can access any of the properties on the object using the standard syntax:

$routeParams.id;

The fallback route

The last route we need to configure is the one that will show when no route is matched. You could create a 404 page for this, but let’s take a look at how we can redirect a route instead of displaying a template.

To create our fallback route, we use the second method that the $routeProvider service gives us—otherwise:

.otherwise({
    redirectTo: '/'
});

Now, if the requested route doesn’t match any of the ones defined in our router, Angular will redirect us back to our index page.

Linking routes

Linking routes is no different than linking to pages on a website. We still use an anchor tag and in place of the link to the page we want to link the route.

For example, if we wanted to link up the Add Contact button in our navbar, we would do the following:

<a href="/add-contact">Add Contact</a>

Angular will automatically display the correct partial when we click the link and also change the URL. If you’ve opted not to use html5Mode, we can still link using an anchor tag, but the href attribute is a little different—we need to add the hash:

<a href="#/add-contact">Add Contact</a>

It’s quite clear what we’re going to need in our Add Contact view—a form to allow us to enter the required information. Thankfully, Bootstrap provides us with a lot of control when arranging our fields. We’ve already worked out what data we’re going to be storing, so it’s just a case of working out what type of field is best:

  • Name: Text field
  • Email address: Email field
  • Phone number: Tel field
  • Address: Textarea
  • Website: Text field
  • Notes: Textarea
  • Gravatar: N/A

As Gravatar uses an email address to serve images, we don’t need to request any additional information here. We’ve got a total of six fields, so I think two columns would be great here.

The first thing we need to do is open up our form. Once we’ve done that, we can add our columns inside. We’ve already got our container class, so we just need to open up a new row and add our two columns. As we learnt in Chapter 2, Let’s Build with angularjs and Bootstrap, Bootstrap’s grid-system is 12-columns wide, so we need to keep that in mind when creating our layout:

<form>
  <div class="row">
    <div class="col-sm-6">

    </div>
    <div class="col-sm-6">

    </div>
  </div>
</form>

Just as before, we’re using the col-sm prefix to allow our columns to collapse down on smaller tablets and mobile devices.

We could just pop our labels and inputs directly within our columns, but for optimum spacing, we need to wrap our elements in a div tag with the form-group class:

<div class="form-group">
  <label for="name">Name</label>
  <input type="text" id="name">
</div>

To take advantage of Bootstrap’s styles in our inputs, we do to add the form-control class to them. If we add the control-label class to our label, it will also give us a bit of extra padding:

<div class="form-group">
  <label for="name" class="control-label">Name</label>
  <input type="text" id="name" class="form-control">
</div>

Let’s quickly add the rest of our elements in. I’m going to add name, phone number, and address to the left column and email address, website, and notes to the right.

Horizontal forms

Okay, that’s looking great. If you’re not a fan of the labels up top, we can position them on the left with a bit of tweaking. By adding the form-horizontal class to our opening form tag, our form-group classes behave as grid rows, meaning we can use column classes in the elements within them. Let me show you what all this means:

<div class="form-group">
  <label for="name" class="col-sm-4 control-label">Name</label>
  <div class="col-sm-8">
    <input type="text" id="name" class="form-control">
  </div>
</div>

After including form-horizontal, you’ll notice we can now add Bootstrap’s column classes to our label. As form-control sets the width to 100%, it matches the parent we need to wrap it in an additional element. As we’ve also included the control-label class, the label is centered vertically.

Our form looks a lot less cluttered using the form-horizontal class, so let’s go ahead and wrap all of our inputs in that form-control element.

There might be times where you need to give the user a bit more information about what’s required. This can be included underneath the related input by using a span tag with the help-block class:

<div class="form-group">
  <label for="notes" class="col-sm-4 control-label">Notes</label>
  <div class="col-sm-8">
    <textarea id="notes" class="form-control"></textarea>
    <span class="help-block">Any additional information about the contact.</span>
  </div>
</div>

The last thing we need to do is add a submit button. In previous versions of Bootstrap, this would usually have been wrapped in an element with the form-actions class. However, in Bootstrap 3, we just need to use the same form-group we’ve been using all along. If you’re using the form-horizontal style, you’ll need to offset your columns:

<div class="form-group">
  <div class="col-sm-offset-4 col-sm-8">
    <button class="btn btn-primary">Add Contact</button>
  </div>
</div>

As our label spans four columns, we need to offset our button the same amount here so it doesn’t look misaligned.

I quite liked the contrast the old form-actions class used to provide. Thankfully, we can achieve a similar result using Bootstrap’s well component. Here, I’ve moved our form-group class containing the submit button to be directly below our existing row (remember, form-horizontal makes all groups act like rows) and have also added a well class:

<div class="form-group well">
  <div class="col-sm-offset-2 col-sm-10">
    <input type="submit" class="btn btn-primary" value="Add Contact">
  </div>
</div>

Finally, to complete the page, I’m going to give it the same page-header element we added to our Index view and position it at the very top of our markup:

<div class="page-header">
  <h1>Add Contact</h1>
</div>

The end result will look as seen in the following screenshot:

Horizontal forms

In this Tutorial, we transformed our application from a single page into a multi-page view and multi-route app that we can build our contacts manager upon. We started by planning out the essential routes in our application before installing the requisite module.

We then looked at how we can use the config method on our own module to set up our routes. This was done by injecting the $routeProvider service and using the when and other methods provided. This allowed us to set up static and dynamic routes containing parameters.