[MUSIC PLAYING] MARK THOMPSON:
Welcome back, friends. And by this point,
if you've been able to complete the
previous modules, you've built a beautiful,
functional application. But since you've
come to this module, that tells me that
you want more, and we can totally do that. Right now, the
application retrieves data from a hardcoded array
in the housing service. Now, to make our app a
little bit more realistic, we can add support to make
HTTP requests for the housing locations. Now, the first change
that we'll make is moving the data
from a hardcoded array in our application into
a standalone server on our local machine that we
can use to make HTTP requests. From the command line, run
npm install -g json-server. Next, we need to create a new
file in the homes-app directory called db.json. Once it's been created,
open it in your editor. In db.json, open the file
and add the following code. Create an empty JSON object. Then add a property wrapped
in quotes called locations. Set the value to
be an empty array. Now, we need entries
for this array, so we'll copy the entries
from our housing service. In housing.service.ts,
copy the array entries from the HousingLocation
list class property and paste them into the
locations array in db.json. Now, to confirm, in db.json,
you should have a JSON object with a property
called locations that has an array value
containing the data entries for the housing locations. Now, let's confirm that
our data is working by starting the JSON server. Here's how. From a command line, run
the following command-- json-server --watch db.json. When the server starts,
you will receive a URL. On my machine, it is
localhost:3000/locations. Opening this URL
in the browser will reveal our data being served
to us from the local server that we've just created. Hey, that's nice work. Now let's update the application
to use our new server. The first change we'll
make is to remove the data from the service. In housing.location.ts,
we're going to remove the
housinglocationlist property and delete the array
of values as well. Now we're going to add
a property called url and set it to the string value
http://localhost:3000/locations. In the getAllHousingLocations
function, we need to make a call
to the API endpoint to retrieve this data. Here's how we'll
accomplish that. First, update the
method signature for getAllHousingLocations
to return a typed promise. The type is housing
and location array. Also mark the function as async. We're going to use the
Fetch API to request data from the local JSON server. In the body of
getAllHousingLocations function, remove
the existing code. Add a constant local
variable called data and set the value to await
fetch and pass in this URL as an argument to fetch. We're using the async
await pattern here to reduce the amount of
code that we have to write and increase the clarity. Next, add a return statement--
return await data.json()-- open-close parentheses because
this is a function call. Then nullish coalescing
operator empty array. If for some reason we
get a nullish value from the call to
data.json, we'll default to returning
an empty array. There's a few
things to note here. We're wrapping the
fetch call in a service which could seem like
adding some complexity here. In this application, we
only make this call once. But in other applications,
we may reuse this same call in multiple places. Also, this gives us the
added benefit of testability. We can provide a
mock implementation of the service in our test
that can return some data. To keep things simple, we're
using the browser Fetch API. For more complex
examples, Angular provides the HTTP client service
class, so you can use that. And to find out more,
head over to Angular.io. OK, great. That function has
been taken care of. We're going to repeat
a lot of these steps for the getHousingLocationById
function. First, let's update
the method signature to return a typed promise. In this case, though, it
will be housingLocation type. In the body of the function,
add a constant local variable called data, set to
the value await fetch. And as a parameter
to fetch, we're going to use JavaScript string
interpolation to construct our URL. Using backticks,
interpolate this.url followed by a forward slash. Then interpolate id,
which is the parameter to getHousingLocationById. Next, add a return statement--
return await data.json(), then nullish coalescing
operator empty object literal. At this point, we've changed the
implementation of the service. But now we have to
update the calls to this service from the other
parts of the application. In home.component.ts,
we're going to update the constructor
method to call the new promise-based service. Remove the existing code
in the body of the function and add a call to
getAllHousingLocations. Next, attach a then
function to the call. For the parameter to
the then function, provide an arrow function. The parameter of the function
is housingLocationList of type HousingLocation array. And in the body of
the function, assign this.housingLocationList, the
value housingLocationList. This is the parameter
that we created. Finally, we'll update
details.component.ts. In the constructor method,
we'll replace the existing call to getHousingLocationById
with a call to our new
promise-based function. Delete the code that assigns a
value to this.housingLocation and add the following. Make a call to
getHousingLocationById in the housing service and pass
in the housingLocationId local variable. Next, attach a then function. As a parameter to
the then function, provide an arrow
function that has a single parameter
called housingLocation of type housingLocation. In the body of the function,
assign this.housingLocation the value housingLocation. Save all of your code. Now, in the browser, we can
confirm that our housing locations are being displayed. We can also confirm that
the application successfully allows users to select
their housing location and be navigated to a
populated details page. Now, we're almost done here,
but there's one more feature I'd like to implement. On the landing page, there's
a search bar and a button that we haven't addressed. Let's turn that into
a functioning filter. To do that, we'll need to
work with a form and a click handler. Open home.component.ts. We need to retrieve the data
from the filter in the template for this component. We could use a form
group and typed forms, but that might be more
than we need for this task. Instead, we'll use something
called a template variable. This will allow us
to get a reference to an element in the template
and use it in our application. Update the input element
and add an attribute of the format #filter. The hashtag syntax creates
our template variable. In this example, the
variable is called filter. Let's update the button element
and add a click handler. Add click, surrounded
by parentheses, and set it equal to the
string value filterResults. And since this is
going to be a function, add parentheses to
the end and pass in filter.value as a parameter. One quick note. You may be wondering where
filter.value came from. Well, since we're using
a template variable, we have access to the
actual HTML element. Value is a property on
the input HTML element. In our click handler
invocation, we're passing in the text
value from the input directly into our
component class. Let's also update the
app-housing-location ngFor code. Right now, we're displaying
the housingLocationList, but we're going to switch
things up. housingLocationList will be our source of truth in
the application for listing. So we're going to change
housingLocationList list to filteredLocationList
in the ngFor. Now we'll update
the component class. Add a new property called
filteredLocationList-- that's all camel case-- of
type housingLocation array and assign it the
value of empty array. In the constructor
and the then function, add a new expression--
this.filteredLocationList equals housingLocationList. Next, we'll update the
filterResults function. First, we'll add code to
check for blank text-- if not text,
this.filteredLocationList equals this.housingLocationList. This allows users to
clear the search box and receive all
housing locations. Next, this is where we'll
handle the actual filtering. this.filteredLocationList equals
this.housingLocationList.filter. Now, the array filter method
takes a callback that defines the criteria, so provide
an arrow function with the parameter housingLocation
and the body of the function to be housingLocation.
name.toLowerCase() because we want to ensure that the census
case doesn't interfere with our comparisons. Continuing, add a call to the
includes function and provide text.toLowerCase() as an
argument to the includes function. Save this code and
return to the browser. In the browser, input
any text and then click the Search button. The results update! This is huge! I am so, so proud of
you and the progress that you've made so far. So here's what's even cooler. Right now, we're
searching or filtering on the name of the
housing location, but you could expand
the filter to compare any fields that you want. All right, friends, we've
covered quite a bit. So let's recap. We've used fetch to make an
HTTP request to a live endpoint. We've refactored our
service and service calls to use a new format. And we've added
filtering capabilities to our application with template
variables and some typescript. All right, way to go! You should be very
excited for your success, and I hope that you are enjoying
the progress that you've made. And at this point,
you have everything you need to get
started on building the next great
application in Angular. Congratulations, friends. Now, there is so
much more to learn, but you are well on your way. I hope that you have
enjoyed this program as I've enjoyed building
this application with you and traveling with you on
your Angular learning journey. OK, friends, until the next
time, go build great apps. [MUSIC PLAYING]