Simple Photo App with Vue.js, Axios, and Flickr API — Part 3
Getting recent photos and searching by place
Previously we refactored our app to be more flexible and DRY. In this article, we’ll add 3 new components to the homepage, which is currently very empty:
- A reusable
HeroSection
component - A
RecentPhotos
component to show the most recently uploaded images from Flickr - A
PlacePhotos
component that allows users to browse photos from a small list of places
Step 1: HeroSection Component
Let’s start with the HeroSection.vue
component. Create a file with that name inside the components
directory and add the following:
- The template consists of one
section
element that will have abackgroundImage
applied to it. Inside it will have atitle
andsubtitle
. These three items will beStrings
the component receives asprops
(lines 12–14), so that we could theoretically use this component again on other page with different images/titles/subtitles. - The
backgroundImage
will be set via an inline:style
attribute (line 2). Normal CSS background images are created with this syntax:
background-image: url('relative-or-external-path.jpg');
- But because we’re doing this in the template we have to use camel case for the CSS style name (
backgroundImage
notbackground-image
) and we employ a method calledheroImagePath()
to construct the path we need.heroImagePath()
(line 18) returns a concatenated a relative path to a file we’ll store inside theassets
directory of our project. Because we’re using Webpack to compile our project files, we have to use therequire()
method to help Webpack find the image we want. - Add responsive CSS styles at the end.
Now visit a website like Unsplash or Pixabay to download a free photo of your choice to serve as the background image. Save it in assets
as homepage-hero.jpg
(or whatever the file extension ends up being).
Next go to Home.vue
and update it to be the following:
We import the HeroSection
component (line 13) and register it (lines 17–19). Then we add it to the template, passing in the necessary props (lines 3–6).
Step 2: RecentPhotos Component
Next let’s create a section on the homepage to show the three most recent photos that have been uploaded to Flickr. We’ll use the flickr.photos.getRecent
method, which requires our api_key
and accepts many similar extra arguments to the flickr.photos.search
method, such as extras
, per_page
, and page
. It will fit perfectly with our flickr.js helper method we made in Part 2. And we’ll use our ImageCard
component to display the images we get.
Create a file named RecentPhotos.vue
inside components
:
- The template consists of a title for the section and a
ul
ofImageCard
components (imported and registered on lines 17 and 21, respectively). Thev-for
loop iterates through a computed property calledmostRecentPhotos
(lines 31–33). mostRecentPhotos
returns the first three images in an array namedrecentPhotos
, stored indata()
.recentPhotos
is initialized to an empty array, which gets filled in with images during thecreated()
lifecycle hook.- In
created()
we call a method,fetchRecentPhotos()
, which uses ourflickr()
helper method (imported on line 15) to make the API call. flickr()
receives two arguments, the method we want to call (photos.getRecent
), and the additional parameters it needs (extras
,page
, andper_page
). If the method request is successfully resolved, we updaterecentPhotos
in thethen()
clause. If there’s an error, we log it to the console in thecatch()
clause.
This will be our standard approach/flow for basically all other API calls throughout this project.
Next, add the component to Home.vue
by importing (line 15) and registering it (line 21), then adding the template tag (line 8).
Disclaimer: If you’re confused why the
ImageCards
don’t always have a super recent date it’s because the date displayed is when the photo was taken, not when it was uploaded, which may not be the same date.
Step 3: PlacePhotos Component
Another popular way to search for photos is by city/place name. Let’s make an interactive component that allows users to browse photos from a limited list of “popular” places. We’ll arbitrarily decide what these places are.
Create a file named PlacePhotos.vue
inside components
. Think of the template as having 3 main parts: there will be a title and list of place name buttons (lines 3 to 16 below). Each button then updates the second part, a list of 3 photos for the selected place (lines 18–31; the second ul
is a loading/skeleton list that appears while the images are being fetched). Third, there will be a link at the bottom that a user can click to view more photos of that place on the SearchResults
page (lines 33–39).
Breaking this down more and starting with the first part, the place-list ul
(lines 4–16):
- The
li
's loop throughpopularPlaces
, an array indata()
that consists of place objects. Each object hasname
andplace_id
properties. Theplace_id
comes from theflickr.places.find
method. Feel free to replace these names and place id’s with others of your choosing! - When a user clicks on the place button, the method
updateSelectedPlaceIndex(index)
is called (line 10).updateSelectedPlaceIndex
accepts one argument, the index of the place object inpopularPlaces
, and updates theselectedPlaceIndex
data property to store that new value. As we’ll see in a minute, this is part of what causes the photos to update.
Next let’s look at the second part, the image-card-grid
ul
on lines 18–24:
- It consists of a list of
ImageCard
s, the images for which come frompopularPlacePhotos
(lines 96–98), a computed property that returns the first three images fromplacePhotos
. placePhotos
is similar torecentPhotos
from the previous component. It starts as an empty array and then gets filled in with image data during thecreated()
lifecycle hook (lines 51–53), this time via thefetchPlacePhotos()
method.fetchPlacePhotos()
(lines 101–115) does the same thing thatfetchRecentPhotos()
did, just with a different API method,photos.search
, and set of parameters.- Line 104 is an important differentiator. We’re searching by
place_id
, nottag
this time. We know whichplace_id
to pass in by indexing intopopularPlaces
using whatever the currentselectedPlaceIndex
value is, then passing in that place’splace_id
. But rather than writing:
place_id: this.popularPlaces[this.selectedPlaceIndex].place_id
we move the first part into its own computed property named selectedPlace
(lines 93–95), allowing us to write:
place_id: this.selectedPlace.place_id
Much more readable.
Lastly, let’s look at the third part of the template (lines 33–39):
- It consists of a center-aligned
<p>
tag that wraps arouter-link
element (aka an<a>
tag). - Line 35 specifies the
name
of the route,searchResults
, and passes in the placename
as the value for our search param,tag
.
The only remaining steps now are to import (line 17) and register (line 24) PlacePhotos.vue
into Home.vue
, and add it to the template (line 9):
And there you have it! Three new components and two more places where we’re calling the Flickr API. Next we’ll add ImageDetail
views to our app so we can click on these cards and see more detailed information about each photo. Thanks for reading and see you then! ✌️