#1: Observable
First Observable!
Our photo gallery looks great, but all photos are so small. Users will want to see bigger pictures. Letβs help them do so! When users click on photo weβll create a nice overlay over our gallery and show the whole photo.
To do it we have to track which photo is currently active. How do we do it? Of course, with help of RxJS! It provides us with BehaviorSubject
β object that holds value changing over time. Once weβve had created BehaviorSubject that stores ID of active photo, we can display it easily. Let's add following code in photos.service.ts
:
Notice the BehaviorSubject constructor takes one argument β initial value. When we start to subscribe to activePhoto$
it will give us this value and, later, every next that comes to it. Our first value is empty string, since thereβs no active photo when application starts.
Let's take a look on our photo.component.html
file
We already know whatβs going on here. Once user clicks on a photo, weβre going to call the onPhotoClick
method with one argument: photo.id
. We want to change value of activePhotoID$
every time user clicks on photo. How do we implement onPhotoClick
to make sure it sends value to activePhotoID$
? We can do so in photo.component.ts
like this:
Tip Remember to inject service in constructor.
Creating new value from Observable
To display active photo letβs create a new Component called (you guessed it) active-photo
. It will access a photo that is currently active and display it.
Tip If you don't remember command to generate component take a look on a previous chapter.
But, you probably thinking now, in our photos service, we only store the ID of the photo. Our Component needs entire Photo object! Letβs take our activePhotoID$
and create new Observable out of it (of course in photos.service.ts
file).
Remember to import propEq
from ramda library:
Only three lines of code and weβre done! This may look complicated, so letβs break down what happens in activePhoto$
and walk through the steps together.
First: weβre accessing current active photo ID.
Second: weβre using pipe
method to transform it into something new. Thatβs what pipe
does. Think of it like a coffee grinder - you put coffee in and get coffee out, but shaped just a little bit differently. It takes value from Observable and pipes it through RxJS operators that create new Observables. Our first pipe
takes photo ID and maps it to Photo object.
Third: we take array of photos and return one Photo whose id
equals photoID
. Function propEq
says exactly that: check if property named id
equals variable photoID
.
Letβs break this process down even further. Letβs extract a method that takes photo ID and returns Photo. It looks like this:
Weβre just finding one photo in array. Now, move it back to our activePhoto$
Observable.
Tip Remember to define function findPhotoByID before its usage.
Take the active photo ID, pipe it through map
operator and return new Observable that finds photo based on ID.
Go on and use activePhoto$
Observable to display photo that user wanted to see!
Display active photo!
It gets more and more interesting! You created BehaviorSubject
that keeps value changing over time. Youβve used it to create new Observable! Now you get to display data from it. It surely requires a lot of work, or does itβ¦? Letβs look at the code.
In active-photo.component.ts
we have to inject PhotoService in component's constructor and add:
Now we can use it in active-photo.component.html
like here:
At the end let's add some styles to our active-photo
component
Looks great but... our component is not visible in the app! To fix it we have to add
in app.component.html
, just below the <app-gallery>
tag.
And we have it with a couple lines of code! You assign activePhoto$
from Photos service to Component field, so we can access activePhoto$
value in HTML. Because we access asynchronous value that changes over time, we need to use the async
pipe. The async
pipe tells Angular it should subscribe to the asynchronous value and use new value every time it changes. Last part ?.url
means: check if activePhoto$
holds a value, if it does access url
field from it and display in HTML. Whew! We did it!
Hiding a photo
Last thing to do is hiding the photo! Itβs nice that user can see bigger photos, but refreshing application every time one wants to change photo preview would be a littleβ¦ cumbersome ;)
To hide active photo we need to put empty ID on activePhotoID$
BehaviorSubject
. This way Photos service will know to send our Components undefined
value through activePhoto$
Observable and no photo will be displayed.
Ok, first letβs add hidePhoto
handler to active-photo.component.html
file, like this:
The active photo is now ready to receive user clicks. Now we go to active-photo.component.ts
and implement our handler.
It looks almost like the code use used in the Photo Compoment to set active Photo ID. Only difference is, this time weβre sending noPhotoID
instead of real ID. This way no active photo is displayed! What more can we do with our gallery? Maybeβ¦ letβs try adding some photos!
Last updated