Outline
Now that we've learned how to display lists of information with Angular,
it'd really be great if we could have the user add posts. To do this,
we first need to add a function to our $scope
variable.
$scope.addPost = function(){
$scope.posts.push({title: 'A new post!', upvotes: 0});
};
When this function is invoked, it will append a new post to our $scope.posts
variable. Now we're going to have to allow the user to actually execute this
function.
<button ng-click="addPost()">Post</button>
Great, we can now click a button and have a new post show up! Let's extend this by allowing the user to actually specify what they want the title to be. First, we need to build out the form in HTML and sprinkle it with some Angular Magic.
<form ng-submit="addPost()">
<input type="text" ng-model="title"></input>
<button type="submit">Post</button>
</form>
Here we've created a form that encompasses our title text-box and 'Post' button.
We are also now calling our addPost()
function using the
ng-submit directive, which has the added benefit of the user being
able to press the 'enter' key to submit the form. Finally, we're using the
ng-model directive to bind the contents of the text box to
$scope
. This will allow our controller to access the contents of the text box
using $scope.title
.
To accompany the changes to our template, we need to make some tweaks to
addPost()
.
title
, and set title
to blank once it has been added to the posts array:
$scope.addPost = function(){
$scope.posts.push({title: $scope.title, upvotes: 0});
$scope.title = '';
};
When we add a post we are now getting the title from $scope.title
, which we
then clear after the post has been created. At this point, it makes sense to
prevent the user from posting a blank title.
addPost()
:
if(!$scope.title || $scope.title === '') { return; }
Enable Upvoting
Now that we can add some new posts, why don't we allow a user to upvote
existing ones? To get started, lets revisit our ng-repeat
directive.
<div ng-repeat="post in posts | orderBy:'-upvotes'">
<span ng-click="incrementUpvotes(post)">^</span>
{{post.title}} - upvotes: {{post.upvotes}}
</div>
We've now added a ^
character inside a <span>
tag that when clicked, calls
the incrementUpvotes()
function in our controller — but we don't have that function in our controller yet!
$scope.incrementUpvotes = function(post) {
post.upvotes += 1;
};
Notice that for this function we are passing the current instance of post
to
the function. This is happening by reference
so when we increment upvotes, it gets automatically reflected back to the HTML page.
Submitting Links
Ultimately, Flapper News is about sharing links to content, so lets enable users to submit links along with their titles. We'll start by adding a second text box to our form that a user can use to submit a link. We'll also add some placeholder text to make it clear which form is which:
link
:
<form ng-submit="addPost()">
<input type="text" placeholder="Title" ng-model="title"></input>
<br>
<input type="text" placeholder="Link" ng-model="link"></input>
<br>
<button type="submit">Post</button>
</form>
addPost()
function to include the link
(notice that we aren't going to force the user to submit a link if they don't
want to):
$scope.addPost = function(){
if(!$scope.title || $scope.title === '') { return; }
$scope.posts.push({
title: $scope.title,
link: $scope.link,
upvotes: 0
});
$scope.title = '';
$scope.link = '';
};
Finally we need to modify the ng-repeat
section to make the title a link
to the content, but only if a link was specified.
We'll do this by using a new directive called ng-hide, which hides elements when an Angular expression evaluates to true.
ng-hide
to hide the linked version of the
title if no link exists and correspondingly show the unlinked version:
<div ng-repeat="post in posts | orderBy:'-upvotes'">
<span ng-click="incrementUpvotes(post)">^</span>
<a ng-show="post.link" href="{{post.link}}">
{{post.title}}
</a>
<span ng-hide="post.link">
{{post.title}}
</span>
- upvotes: {{post.upvotes}}
</div>
It is worth noting that ng-show is merely the inverse of ng-hide
. You can use either one for programmatically displaying and hiding elements.