As you can see, the code we end up needing after we build and call in our component is neat and clean and compact. Once it's in the DOM, each component instance shown below is replaced by the original html from the template we put in the catfolio component, along with whichever breed/stats the prop "thiscat" is telling it should be displayed. It's so cool that all you have to change is a few letters to get multiple sets of information, and you only have to build and style it once!
<body>
<h1>Top Cats Stats</h1>
<div id="britcat">
<catfolio thiscat="bslo"></catfolio><br><hr>
<catfolio thiscat="birm"></catfolio><br><hr>
<catfolio thiscat="ctif"></catfolio><br><hr>
<catfolio thiscat="bamb"></catfolio><br><hr>
<catfolio thiscat="emau"></catfolio><br>
</div>
</body>
Vue.component ('catfolio', {
props: {
thiscat: String,
},
I dubbed my component "catfolio" and created a prop to use with "whichcat," which calls the breed information from the specified breeds object in the massive cat array. With the prop (using various breed IDs), I can change the contents of my component in the html without having to change the component itself or create separate components.
What each property inside the mustache braces in the template displays on the webpage is based on the breed ID used with "whichcat"/"thiscat" as well as the value targeted with the corresponding variable in the data.
template:
`<div>
<h2>{{ thename }}</h2>
<h3>Origin: {{ origin }}</h3>
<h3>Overview: {{ description }}</h3>
<h3 id="fix-text"><span>Top</span> traits: {{ personality }}</h3>
<div id="other-stats">
<h3>Energy ({{ pep }}/5)</h3>
<div id="hyper" :style="{ width: howHyper }"> </div>
<h3>Intelligence ({{ smart }}/5)</h3>
<div id="smart" :style="{ width: howSmart }"> </div>
<h3>Affection ({{ sweets }}/5)</h3>
<div id="sweets" :style="{ width: howSweets }"> </div>
<h3>Shedding ({{ furry }}/5)</h3>
<div id="fur" :style="{ width: howFurry }"> </div>
<h3>Health Issues ({{ sick }}/5)</h3>
<div id="health" :style="{ width: howSick }"> </div>
</div><br>
<button v-on:click="slideshow()">See More {{ thename }}s</button><br><br>
<img :src="image.url"><br>
</div>`,
In the return braces, we set our variables we use to call the data from the API. This is also where I altered "whichcat," which originally took a single breed ID, by connecting it to my component prop "thiscat." As mentioned, the prop allows me to reuse the component template with multiple breeds simply by changing the prop value in the html to a different breed ID.
data () {
return {
image: "",
whichcat: this.thiscat,
thename: "",
description: "",
personality: "",
origin: "",
allofit: [],
i: 0,
adapt: 0,
pep: "",
smart: "",
sweets:"",
furry: "",
sick: "",
}
},
This is the part of the code that I am least familiar with, but I will try my best. I do know that we are tying whichcat to the breed ID in the first part. We also call the information from the API asynchronously because we don't want the browser to go through this code one line at a time. We are looping through a large array, a lot of information. So we are telling it to load everything as it can but not wait and get stuck on one part before it does something else we need it to do, basically, I think... After we get our data request in place, we begin using our other variables to access specific attributes.
created() {
this.loadNextImage(this.whichcat);
},
methods: {
async loadNextImage(breedID) {
try {
axios.defaults.headers.common['x-api-key'] =
"5707ff43-c0b5-456f-864a-78a03c24ea46"
let response = await axios.get
('https://api.thecatapi.com/v1/images/search?breed_ids=' + breedID, {
params: {
limit: 10,
size: "full"
}
})
let theid = response.data[0].id;
let response2 = await axios.get
('https://api.thecatapi.com/v1/images/' + theid, {})
this.adapt = response2.data.breeds[0].adaptability;
this.thename = response2.data.breeds[0].name;
I pulled out more information about each cat by using the response2 variable to access specific properties in the breeds objects with dot and bracket notation. The catch is there in case something goes wrong with our API request. We ask for that information to be stuck in the console so we can try to resolve it.
this.description = response2.data.breeds[0].description;
this.personality = response2.data.breeds[0].temperament;
this.origin = response2.data.breeds[0].origin;
this.pep = response2.data.breeds[0].energy_level;
this.smart = response2.data.breeds[0].intelligence;
this.sweets = response2.data.breeds[0].affection_level;
this.furry = response2.data.breeds[0].shedding_level;
this.sick = response2.data.breeds[0].health_issues;
this.allofit = response.data;
} catch (err) {
console.log(err)
}
this.slideshow()
},
The method below keeps the slideshow part of the div looping through the images. Were it not there, eventually you would hit the end of the slideshow, and nothing would happen. By telling it we only want it to go to the last image in the bunch and then start over, we keep it going. We see async here again because it's important to give the browser time to load everything but not get stuck on a particularly large image and display nothing.
async slideshow() {
if (this.i >= this.allofit.length) {
this.i = 0;
}
this.image = this.allofit[this.i];
this.i++;
},
},
Our images were conveniently set in the starter CSS at 500px wide, and the number values returned by each cat object for the various traits happened to range from 1 to 5. I decided to create computed properties to display that trait information in graphic form. By concatenating the values returned by the methods above with "00px," we get brand new values that range from 100px to — at max — 500px. Sweet! That's the same width as our images. We can then use a style binding to set the width of a div to the value of a corresponding computed property. There may be a more elegant way to do this, but this way works!!
computed: {
howHyper() {
return this.pep + "00px";
},
howSmart() {
return this.smart + "00px";
},
howFurry() {
return this.furry + "00px";
},
howSick() {
return this.sick + "00px";
},
howSweets() {
return this.sweets + "00px";
},
}
})
Finally, at the bottom, the el "#britcat" is how we tell Vue where in the html to mount the components (inside the div with the matching id of "britcat"). El can also be used with class and other attributes.
var topcat = new Vue ({
el: '#britcat'
})