Outline

Now that we've figured out how to create a state with ui-router, let's create a new one called posts that will display comments associated with a post.

In the config block in app.js, add a state where an individual post can be accessed:
.state('posts', {
  url: '/posts/{id}',
  templateUrl: '/posts.html',
  controller: 'PostsCtrl'
});

Notice that we define our URL with brackets around 'id'. This means that 'id' is actually a route parameter that will be made available to our controller.

As with the home state, we're also going to need to define both a new template and a new controller. Because we're going to associate comments with posts, we want to ensure our posts factory is injected into this controller so that it may access the comments data.

Create a new controller in app.js called PostsCtrl and be sure to inject the posts service:
.controller('PostsCtrl', [
'$scope',
'$stateParams',
'posts',
function($scope, $stateParams, posts){

}]);

Faking comment data

Before we go any further, let's take a second to add some fake comment data to our posts model. This will help us mock up the basic comments view as well as ensure our routing is working properly.

In our addPost function in MainCtrl, add an array of fake comments to the posts object:
$scope.posts.push({
  title: $scope.title,
  link: $scope.link,
  upvotes: 0,
  comments: [
    {author: 'Joe', body: 'Cool post!', upvotes: 0},
    {author: 'Bob', body: 'Great idea but everything is wrong!', upvotes: 0}
  ]
});

Getting the Right Post

Since the posts page is about viewing the comments on a particular post, we need to use the id route parameter to grab the post and associated information. For now, we will consider the index of the post to be its id. We can use $stateParams to retrieve the id from the URL and load the appropriate post.

In PostsCtrl, set a scope object called post that grabs the appropriate post from the posts service using the id from $stateParams:
$scope.post = posts.posts[$stateParams.id];

Now that we have the post variable in our controller, we can display that information in our template.

Create a new inline template called "/posts.html" in index.html right before the </body> tag:
<script type="text/ng-template" id="/posts.html">
  <div class="page-header">
    <h3>
      <a ng-show="post.link" href="{{post.link}}">
        {{post.title}}
      </a>
      <span ng-hide="post.link">
        {{post.title}}
      </span>
    </h3>
  </div>

  <div ng-repeat="comment in post.comments | orderBy:'-upvotes'">
    <span class="glyphicon glyphicon-thumbs-up"
      ng-click="incrementUpvotes(comment)"></span>
    {{comment.upvotes}} - by {{comment.author}}
    <span style="font-size:20px; margin-left:10px;">
      {{comment.body}}
    </span>
  </div>
</script>

Finally, we'll add a link to the post's comment page next to the headline on the front page.

In the "/home.html" inline template, add the code below right after the title </span> tag:
<span>
  <a href="#/posts/{{$index}}">Comments</a>
</span>

When iterating over an array, the ng-repeat directive makes an $index variable available along with each item in the array.

Creating New Comments

As with the creation of posts, we're going to want to allow our users to post new comments. This code looks very similar to what we've already written:

In our controller PostsCtrl, create an addComment function:
$scope.addComment = function(){
  if($scope.body === '') { return; }
  $scope.post.comments.push({
    body: $scope.body,
    author: 'user',
    upvotes: 0
  });
  $scope.body = '';
};
Add the form below at the end of our inline template "/posts.html":
<script type="text/ng-template" id="/posts.html">

  <!-- post template -->

  <form ng-submit="addComment()"
    style="margin-top:30px;">
    <h3>Add a new comment</h3>

    <div class="form-group">
      <input type="text"
      class="form-control"
      placeholder="Comment"
      ng-model="body"></input>
    </div>
    <button type="submit" class="btn btn-primary">Post</button>
  </form>
</script>

Recap

In this first section, we've introduced you to some of the very basics of Angular.js including data-binding, controllers, services, and routing. In the process, we've created a skeleton web application that allows a user to create a posting that can contain a link or a title, then create comments that are associated with those postings.

Up next we're going to learn how to use Rails to implement a basic REST API for saving and retrieving posts and comments. Then we'll come back to the frontend and wire everything together into a single cohesive and functional web application.

 

I finished! On to the next chapter