In this project, we'll create an Angular application that displays a list of your friends. The list will be searchable and filterable through user interaction. You can see a live demo by clicking on the link below.
- Fork and clone this repository.
- Open the project directory in your coding IDE.
In this step, we'll create the skeleton of our Angular application.
- Create a
js
folder at the root of the project. - Create an
app.js
file injs/
. - Create a
friendCtrl.js
file injs/
. - Open
js/app.js
and create a new Angular application called"myApp"
. - Open
js/friendCtrl.js
and create a controller calledfriendCtrl
.- Add a scope variable called test that equals
"Connected"
.
- Add a scope variable called test that equals
- Open
index.html
. - Add a
script
tag for the Angular CDN. - Add a
script
tag forjs/app.js
. - Add a
script
tag forjs/friendCtrl.js
. - Add
ng-app
andng-controller
to the HTML. - Verify your
app
andcontroller
are connected by adding{{ test }}
to the HTML.- If
Connected
appears on the DOM, remove{{ test }}
from the HTML and$scope.test
fromjs/friendCtrl.js
.
- If
Detailed Instructions
Let's begin by creating a js
folder at the root of the project. We'll use this folder to hold all our Angular javascript files. Inside this folder, create two new files: app.js
and friendCtrl.js
. We'll create our Angular application in js/app.js
. Let's open this file and create an Angular application called myApp
.
angular.module("myApp", []);
Take note of the empty array after "myApp"
, this is what tells Angular we are creating a new application. When we reference myApp
we don't include the array again. We'll see an example of this when we create our controller. Now that our Angular application is made, let's make an Angular controller called friendCtrl
in js/friendCtrl.js
.
angular.module("myApp").controller("friendCtrl", function( $scope ) {
}
As you can see, we did not use angular.module("myApp", [])
but instead angular.module("myApp")
. Now that we have our Angular app and controller, let's link the Angular CDN, our app, and our controller to index.html
under <!-- your scripts here -->
.
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.6/angular.min.js"></script>
<script src="js/app.js"></script>
<script src="js/friendCtrl.js"></script>
Now that our index.html
has access to Angular, our app, and our controller, we can edit the HTML to use our app and controller. On the opening html
tag let's add the ng-app
attribute and set it equal to the name of our app ( myApp
). And on the opening body
tag let's add the ng-controller
attribute and set it equal to the name of our controller ( friendCtrl
).
<html ng-app="myApp">
<body ng-controller="friendCtrl">
index.html
<!DOCTYPE html>
<html ng-app="myApp">
<head>
<title>Angular Friends</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css">
<link rel="stylesheet" type="text/css" href="styles.css">
</head>
<body ng-controller="friendCtrl">
<h1>The <strong>facebook</strong> Friend Machine</h1>
<div class="friends">
<form class="form-inline searchForm" role="form">
<div class="form-group">
<input class="form-control" placeholder="Search Anything About Your Friends">
<select class="input-medium">
<option>Name</option>
<option>#Friends</option>
<option>City</option>
<option>State</option>
<option>Country</option>
</select>
<select class="input-medium">
<option value="-">Descending</option>
<option value="+">Ascending</option>
</select>
</div>
</form>
<ul>
<li class='friend'>
<img class="profile-pic" src='http://placebear.com/50/50.jpg'>
<h3>Cali Fornia</h3>
<div class="location">
Location: New Port Beach, California, United States
</div>
<div class="status">
Status: I hate the snow. I wish I was on the beach right now!!!
</div>
<div class="num-friends">
Friends: 1,367
</div>
</li>
</ul>
</div>
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<!-- your scripts here -->
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.6/angular.min.js"></script>
<script src="js/app.js"></script>
<script src="js/friendCtrl.js"></script>
</body>
</html>
js/app.js
angular.module("myApp", []);
js/friendCtrl.js
angular.module("myApp").controller("friendCtrl", function( $scope ) {
});
In this step, we'll add mock friend data to scope in js/friendCtrl.js
and the display it in the HTML.
- Open
mock-data.json
and copy all the contents inside the file. - Open
js/friendCtrl.js
. - Add a
scope
variable calledfriends
that equals what you copied frommock-data.json
. - Open
index.html
and locate theul
element. - Underneath the only
li
element, add a newli
element that usesng-repeat
.- Each friend object has the following properties:
name
- stringpic-square
- stringlocation
- objectcity
- stringstate
- stringcountry
- string
status
- string || nullfriend_count
- number
- Follow the format of hard-coded
li
element.
- Each friend object has the following properties:
Detailed Instructions
Let's begin by opening js/friendCtrl.js
and adding a new $scope
variable called friends
that equals the array inside of mock-data.json
.
angular.module("myApp").controller("friendCtrl", function( $scope ) {
$scope.friends = // array from mock-data.json
}
Now that our mock data is on $scope
we can access it in our HTML
. Using the ng-repeat
attribute we can create a new li
element that will loop through $scope.friends
. We'll want our li
element to follow the same format as the one provided. If you're not sure what properties are on each friend
object, you can add a console.log
in js/friendCtrl.js
to log the value of $scope.friends
. You should end up with an li
element that looks like:
<li class="friend" ng-repeat="friend in friends">
<img class="profile-pic" ng-src="{{friend.pic_square}}" />
<h3>{{ friend.name }}</h3>
<div class="location">
Location: {{ friend.location.city }}, {{ friend.location.state }}, {{ friend.location.country }}
</div>
<div class="status">
Status: {{ friend.status }}
</div>
<div class="num-friends">
Friends: {{ friend.friend_count }}
</div>
</li>
index.html
<!DOCTYPE html>
<html ng-app="myApp">
<head>
<title>Angular Friends</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css">
<link rel="stylesheet" type="text/css" href="styles.css">
</head>
<body ng-controller="friendCtrl">
<h1>The <strong>facebook</strong> Friend Machine</h1>
<div class="friends">
<form class="form-inline searchForm" role="form">
<div class="form-group">
<input class="form-control" placeholder="Search Anything About Your Friends">
<select class="input-medium">
<option>Name</option>
<option>#Friends</option>
<option>City</option>
<option>State</option>
<option>Country</option>
</select>
<select class="input-medium">
<option value="-">Descending</option>
<option value="+">Ascending</option>
</select>
</div>
</form>
<ul>
<li class='friend'>
<img class="profile-pic" src='http://placebear.com/50/50.jpg'>
<h3>Cali Fornia</h3>
<div class="location">
Location: New Port Beach, California, United States
</div>
<div class="status">
Status: I hate the snow. I wish I was on the beach right now!!!
</div>
<div class="num-friends">
Friends: 1,367
</div>
</li>
<li class="friend" ng-repeat="friend in friends">
<img class="profile-pic" ng-src="{{friend.pic_square}}" />
<h3>{{ friend.name }}</h3>
<div class="location">
Location: {{ friend.location.city }}, {{ friend.location.state }}, {{ friend.location.country }}
</div>
<div class="status">
Status: {{ friend.status }}
</div>
<div class="num-friends">
Friends: {{ friend.friend_count }}
</div>
</li>
</ul>
</div>
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<!-- your scripts here -->
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.6/angular.min.js"></script>
<script src="js/app.js"></script>
<script src="js/friendCtrl.js"></script>
</body>
</html>
js/friendCtrl.js
angular.module("myApp").controller("friendCtrl", function( $scope ) {
$scope.friends = // array from mock-data.json
});
In this step, we will add a filter to our ng-repeat
.
- Open
js/friendCtrl.js
. - Add a new
scope
variable calledsearchTerm
and default it to an empty string. - Open
index.html
. - Update the input with the class of
.form-control
to use anng-model
ofsearchTerm
. - Update the
li
element with theng-repeat
to filter bysearchTerm
.
Detailed Instructions
Let's begin by opening js/friendCtrl.js
and adding a new $scope
variable called searchTerm
that equals ""
. We'll use this variable as the ng-model
for the input
element in our HTML. The ng-model
will then capture what we type in the input
element.
angular.module("myApp").controller("friendCtrl", function( $scope ) {
$scope.friends = // array from mock-data.json
$scope.searchTerm = "";
});
Open index.html
and locate the input
element with the class of .form-control
. Add a ng-model
attribute to it that equals searchTerm
. Now that the input
element is hooked up to searchTerm
we can modify our ng-repeat
attribute to include a filter based on the value of searchTerm
. To add a filter to ng-repeat
all you have to do is include a |
and then filter:scopeVariable
.
<input class="form-control" placeholder="Search Anything About Your Friends" ng-model="searchTerm">
<li class="friend" ng-repeat="friend in friends | filter:searchTerm">
You can now test filtering your friends using the input field.
index.html
<!DOCTYPE html>
<html ng-app="myApp">
<head>
<title>Angular Friends</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css">
<link rel="stylesheet" type="text/css" href="styles.css">
</head>
<body ng-controller="friendCtrl">
<h1>The <strong>facebook</strong> Friend Machine</h1>
<div class="friends">
<form class="form-inline searchForm" role="form">
<div class="form-group">
<input class="form-control" placeholder="Search Anything About Your Friends" ng-model="searchTerm">
<select class="input-medium">
<option>Name</option>
<option>#Friends</option>
<option>City</option>
<option>State</option>
<option>Country</option>
</select>
<select class="input-medium">
<option value="-">Descending</option>
<option value="+">Ascending</option>
</select>
</div>
</form>
<ul>
<li class='friend'>
<img class="profile-pic" src='http://placebear.com/50/50.jpg'>
<h3>Cali Fornia</h3>
<div class="location">
Location: New Port Beach, California, United States
</div>
<div class="status">
Status: I hate the snow. I wish I was on the beach right now!!!
</div>
<div class="num-friends">
Friends: 1,367
</div>
</li>
<li class="friend" ng-repeat="friend in friends | filter:searchTerm">
<img class="profile-pic" ng-src="{{friend.pic_square}}" />
<h3>{{ friend.name }}</h3>
<div class="location">
Location: {{ friend.location.city }}, {{ friend.location.state }}, {{ friend.location.country }}
</div>
<div class="status">
Status: {{ friend.status }}
</div>
<div class="num-friends">
Friends: {{ friend.friend_count }}
</div>
</li>
</ul>
</div>
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<!-- your scripts here -->
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.6/angular.min.js"></script>
<script src="js/app.js"></script>
<script src="js/friendCtrl.js"></script>
</body>
</html>
js/friendCtrl.js
angular.module("myApp").controller("friendCtrl", function( $scope ) {
$scope.friends = // array from mock-data.json
$scope.searchTerm = "";
});
In this step, we'll refactor the current filter to be more specific. Instead of a filter that will search the entire friend object, we will narrow it down to name
and state
.
- Open
js/friendCtrl.js
. - Remove
searchTerm
fromscope
. - Create a new
scope
variable calledfilters
that equals an object with the following properties:name
- This should default to an empty string.state
- This should default to an empty string.
- Open
index.html
. - Delete the original
input
and replace it with the following HTML:-
input HTML
<input class="form-control" placeholder="Search Name"> <input class="form-control" placeholder="Search State">
-
- Modify the new
input
elements to use the correctng-model
.- Hint:
$scope.filters.name
and$scope.filters.state
.
- Hint:
- Modify the filter in the
ng-repeat
to specifically filter byname
andstate
.- Hint: You can filter specifically by using object-like syntax.
-
Hint
filter:{ property: scopeVariable, property: { property: scopeVariable } }
-
- Hint: You can filter specifically by using object-like syntax.
Detailed Instructions
Let's begin by opening js/friendCtrl.js
and removing searchTerm
from $scope
. Instead of just filtering through every property of a friend
object, let's make an object that will contain specific filters. Let's call our new variable $scope.filters
and add name
and state
as properties on it.
angular.module("myApp").controller("friendCtrl", function( $scope ) {
$scope.friends = // array from mock-data.json
$scope.filters = {
name: '',
state: ''
};
});
Now let's open index.html
and apply our new $scope
variable as a ng-model
. Let's get rid of the input
that's already there and replace it with two inputs.
<input class="form-control" placeholder="Search Name">
<input class="form-control" placeholder="Search State">
We can then apply our ng-model
to these inputs using dot
notation. For the input
element with the placeholder of Search Name
let's apply filters.name
as its ng-model
. And let's apply filters.state
as the other input
element's ng-model
.
<input class="form-control" placeholder="Search Name" ng-model="filters.name">
<input class="form-control" placeholder="Search State" ng-model="filters.state">
We can then modify the ng-repeat
filter to use our new ng-models
. In Angular, when you want to use multiple filters we use an object-like syntax rather than filter:scopeVariable
. So if we wanted to filter by name, we would do:
<li class="friend" ng-repeat="friend in friends | filter:{ name: filters.name }">
The tricky part here is adding a filter for state
because state
is a property on a nested object. Luckily Angular allows us to filter by nested properties as long as we provided the parent object. This would look like:
<li class="friend" ng-repeat="friend in friends | filter:{ name: filters.name, location: { state: filters.state } }">
Now you can test filtering specifically by a friend's name or state.
index.html
<!DOCTYPE html>
<html ng-app="myApp">
<head>
<title>Angular Friends</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css">
<link rel="stylesheet" type="text/css" href="styles.css">
</head>
<body ng-controller="friendCtrl">
<h1>The <strong>facebook</strong> Friend Machine</h1>
<div class="friends">
<form class="form-inline searchForm" role="form">
<div class="form-group">
<input class="form-control" placeholder="Search Name" ng-model="filters.name">
<input class="form-control" placeholder="Search State" ng-model="filters.state">
<select class="input-medium">
<option>Name</option>
<option>#Friends</option>
<option>City</option>
<option>State</option>
<option>Country</option>
</select>
<select class="input-medium">
<option value="-">Descending</option>
<option value="+">Ascending</option>
</select>
</div>
</form>
<ul>
<li class='friend'>
<img class="profile-pic" src='http://placebear.com/50/50.jpg'>
<h3>Cali Fornia</h3>
<div class="location">
Location: New Port Beach, California, United States
</div>
<div class="status">
Status: I hate the snow. I wish I was on the beach right now!!!
</div>
<div class="num-friends">
Friends: 1,367
</div>
</li>
<li class="friend" ng-repeat="friend in friends | filter:{ name: filters.name, location: { state: filters.state } }">
<img class="profile-pic" ng-src="{{friend.pic_square}}" />
<h3>{{ friend.name }}</h3>
<div class="location">
Location: {{ friend.location.city }}, {{ friend.location.state }}, {{ friend.location.country }}
</div>
<div class="status">
Status: {{ friend.status }}
</div>
<div class="num-friends">
Friends: {{ friend.friend_count }}
</div>
</li>
</ul>
</div>
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<!-- your scripts here -->
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.6/angular.min.js"></script>
<script src="js/app.js"></script>
<script src="js/friendCtrl.js"></script>
</body>
</html>
js/friendCtrl.js
angular.module("myApp").controller("friendCtrl", function( $scope ) {
$scope.friends = // array from mock-data.json
$scope.filters = {
name: '',
state: ''
};
});
In this step, we'll add the option to sort our friends by their properties in ascending and descending order.
- Open
js/friendCtrl.js
. - Add a new
scope
property calledsorts
that equals an object with the following properties:property
- This should default to"name"
.direction
- This should default to"+"
.
- Open
index.html
. - Assign the correct
ng-model
to the twoselect
elements. - Add a
value
attribute to eachoption
element in the firstselect
element.- This should equal the corresponding
property
on thefriend
object.
- This should equal the corresponding
- Add an
orderBy
to theng-repeat
to order byproperty
anddirection
.
Detailed Instructions
Let's being by opening js/friendCtrl.js
and adding a new $scope
variable called sorts
. This will be an object to hold the ng-model
values for sorting. We'll need two properies on this object: property
- we'll use this to determine which property to sort by and direction
- we'll use this to determine whether to display in ascending or decsending order.
angular.module("myApp").controller("friendCtrl", function( $scope ) {
$scope.friends = // array from mock-data.json
$scope.filters = {
name: '',
state: ''
};
$scope.sorts = {
property: 'name',
direction: '+'
};
});
We can then assign property
and direction
as ng-models
to the the select
elements in index.html
<select class="input-medium" ng-model="sorts.property">
<select class="input-medium" ng-model="sorts.direction">
Before our ng-model
will work with our first select
element, we'll need to assign a value
attribute to each option
element. Otherwise our ng-model
will never get updated with a value. Since this ng-model
is looking for a friend property
the value of each option must be spelt exactly the same as it is for each friend
object. You can view what the property names are on a friend object by adding console.log( $scope.friends )
in js/friendCtrl.js
. You should end up with:
<select class="input-medium" ng-model="sorts.property">
<option value="name">Name</option>
<option value="friend_count">#Friends</option>
<option value="location.city">City</option>
<option value="location.state">State</option>
<option value="location.country">Country</option>
</select>
Now that our ng-models
are ready to be used, all that's left is to add another |
and orderBy
to our ng-repeat
. orderBy
wokrs by using +
for ascending and -
for decsending. That's why the second select
element uses +
and -
as its option values. The +
or -
needs to be immediately followed by a property to order by. So for example, ascending order by name would look like: +name
. We can make this dynamic by using our $scope.sorts
variable.
<li class="friend" ng-repeat="friend in friends | filter:{ name: filters.name, location: { state: filters.state } } | orderBy: sorts.direction + sorts.property">
You can now test ordering your friends by different properties.
index.html
<!DOCTYPE html>
<html ng-app="myApp">
<head>
<title>Angular Friends</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css">
<link rel="stylesheet" type="text/css" href="styles.css">
</head>
<body ng-controller="friendCtrl">
<h1>The <strong>facebook</strong> Friend Machine</h1>
<div class="friends">
<form class="form-inline searchForm" role="form">
<div class="form-group">
<input class="form-control" placeholder="Search Name" ng-model="filters.name">
<input class="form-control" placeholder="Search State" ng-model="filters.state">
<select class="input-medium" ng-model="sorts.property">
<option value="name">Name</option>
<option value="friend_count">#Friends</option>
<option value="location.city">City</option>
<option value="location.state">State</option>
<option value="location.country">Country</option>
</select>
<select class="input-medium" ng-model="sorts.direction">
<option value="-">Descending</option>
<option value="+">Ascending</option>
</select>
</div>
</form>
<ul>
<li class='friend'>
<img class="profile-pic" src='http://placebear.com/50/50.jpg'>
<h3>Cali Fornia</h3>
<div class="location">
Location: New Port Beach, California, United States
</div>
<div class="status">
Status: I hate the snow. I wish I was on the beach right now!!!
</div>
<div class="num-friends">
Friends: 1,367
</div>
</li>
<li class="friend" ng-repeat="friend in friends | filter:{ name: filters.name, location: { state: filters.state } } | orderBy: sorts.direction + sorts.property">
<img class="profile-pic" ng-src="{{friend.pic_square}}" />
<h3>{{ friend.name }}</h3>
<div class="location">
Location: {{ friend.location.city }}, {{ friend.location.state }}, {{ friend.location.country }}
</div>
<div class="status">
Status: {{ friend.status }}
</div>
<div class="num-friends">
Friends: {{ friend.friend_count }}
</div>
</li>
</ul>
</div>
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<!-- your scripts here -->
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.6/angular.min.js"></script>
<script src="js/app.js"></script>
<script src="js/friendCtrl.js"></script>
</body>
</html>
js/friendCtrl.js
angular.module("myApp").controller("friendCtrl", function( $scope ) {
$scope.friends = // array from mock-data.json
$scope.filters = {
name: '',
state: ''
};
$scope.sorts = {
property: 'name',
direction: '+'
};
});
Create the filter using ng-options
instead.
If you see a problem or a typo, please fork, make the necessary changes, and create a pull request so we can review your changes and merge them into the master repo and branch.
© DevMountain LLC, 2017. Unauthorized use and/or duplication of this material without express and written permission from DevMountain, LLC is strictly prohibited. Excerpts and links may be used, provided that full and clear credit is given to DevMountain with appropriate and specific direction to the original content.