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.
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.
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.
$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.
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.
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.
</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:
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 = '';
};
<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.