Simple Photo App with Vue.js, Axios, and Flickr API — Part 3

Getting recent photos and searching by place

Nathan Magyar
6 min readApr 5, 2019

Part 1 | Part 2 | Part 3:

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 a backgroundImage applied to it. Inside it will have a title and subtitle. These three items will be Strings the component receives as props (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 not background-image) and we employ a method called heroImagePath() to construct the path we need. heroImagePath() (line 18) returns a concatenated a relative path to a file we’ll store inside the assets directory of our project. Because we’re using Webpack to compile our project files, we have to use the require() 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 of ImageCard components (imported and registered on lines 17 and 21, respectively). The v-for loop iterates through a computed property called mostRecentPhotos (lines 31–33).
  • mostRecentPhotos returns the first three images in an array named recentPhotos, stored in data().
  • recentPhotos is initialized to an empty array, which gets filled in with images during the created() lifecycle hook.
  • In created() we call a method, fetchRecentPhotos(), which uses our flickr() 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, and per_page). If the method request is successfully resolved, we update recentPhotos in the then() clause. If there’s an error, we log it to the console in the catch() 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 through popularPlaces, an array in data() that consists of place objects. Each object has name and place_id properties. The place_id comes from the flickr.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 in popularPlaces, and updates the selectedPlaceIndex 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 ImageCards, the images for which come from popularPlacePhotos (lines 96–98), a computed property that returns the first three images from placePhotos.
  • placePhotos is similar to recentPhotos from the previous component. It starts as an empty array and then gets filled in with image data during the created() lifecycle hook (lines 51–53), this time via the fetchPlacePhotos() method.
  • fetchPlacePhotos() (lines 101–115) does the same thing that fetchRecentPhotos() 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, not tag this time. We know which place_id to pass in by indexing into popularPlaces using whatever the current selectedPlaceIndex value is, then passing in that place’s place_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 a router-link element (aka an <a> tag).
  • Line 35 specifies the name of the route, searchResults, and passes in the place name 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! ✌️

--

--

Nathan Magyar

User Experience Designer and Front End Developer, University of Michigan Office of Academic Innovation