I am a student building a simple web app for interacting with Google Books API. I have a random word being generated as the Google Books search parameter, which is returning in JSON correctly.
The problem is, some books do not have an "Author"/"Description"/"Image" parameter to return. For Author/Desc, I've accounted for this easily using a ternary, but the ternary isn't working out so well for an image source.
What I'm trying to achieve- IF the Google Books query has a value for Image, return that image: ELSE, return a default value of my choosing, in this case 'http://clipart-library.com/newimages/clip-art-books-15.png'. I would rather not edit the HTML to achieve this.
Perhaps there is a better way to do this than through ternary. Can anyone advise?
const testBookImg2 is the ternary of focus.
fetch (randomWord)
.then (res => res.json())
.then (obj => {
console.log(obj)
fetch (gbooks + obj[0])
.then (res => res.json())
.then (obj2 => {
const testdesc1 = obj2.items[0].volumeInfo.description
const testdesc2 = typeof(testdesc1) !== 'undefined' ? testdesc1 : 'No Description Provided'
const testAuthor1 = obj2.items[0].volumeInfo.authors
const testAuthor2 = typeof(testAuthor1) !== 'undefined' ? testAuthor1 : 'No Author'
selectedBookDescription.innerText = testdesc2
selectedBookAuthor.innerText = testAuthor2
selectedBookTitle.innerText = obj2.items[0].volumeInfo.title
const testBookImg1 = obj2.items[0].volumeInfo.imageLinks.thumbnail
const testBookLink = 'http://clipart-library.com/newimages/clip-art-books-15.png'
const testBookImg2 = typeof(testBookImg1) !== 'undefined' ? testBookImg1 : `${testBookLink}`
selectedBookImage.src = testBookImg2
})
})
The problem is that there's no imageLinks property, so you get an error trying to read the thumbnail property of undefined.
Use the optional chaining operator to prevent this errors. It will assign the value of the property if it exists, or undefined if it doesn't exist or any of the intermediate properties don't exist.
const testBookImg1 = obj2.items[0]?.volumeInfo?.imageLinks?.thumbnail;
const testBookLink = 'http://clipart-library.com/newimages/clip-art-books-15.png';
const testBookImg2 = typeof testBookImg1 !== 'undefined' ? testBookImg1 : || testBookLink;
There's no need to use a template literal around testBookLink, since it's already a string.
This will set testBookImg1 to undefined if any of the intermediate properties doesn't exist.
There are a couple of ways to handle optional keys on objects:
const obj = {
key1: "val1",
}
const keyIn = (key, obj) => key in obj
const hasOwnProperty = (key, obj) => obj.hasOwnProperty(key)
console.log('key1 in obj', keyIn('key1', obj))
console.log('key2 in obj', keyIn('key2', obj))
console.log('key1 hasOwnProperty with obj', hasOwnProperty('key1', obj))
console.log('key2 hasOwnProperty with obj', hasOwnProperty('key2', obj))
Also, you could use the nullish coalescing operator - ??:
(function() {
const testBookImg1 = 'valid string'
const testBookLink = 'http://clipart-library.com/newimages/clip-art-books-15.png'
const testBookImg2 = testBookImg1 ?? testBookLink
console.log('testBookImg2', testBookImg2)
})();
(function() {
const testBookImg1 = undefined
const testBookLink = 'http://clipart-library.com/newimages/clip-art-books-15.png'
const testBookImg2 = testBookImg1 ?? testBookLink
console.log('testBookImg2', testBookImg2)
})();
// mock object
const obj2 = {
items: [{
volumeInfo: {
imageLinks: {
thumbnail: 'valid thumbnail src'
}
}
}]
}
const testBookImg1 = obj2?.items[0]?.volumeInfo?.imageLinks?.thumbnail
const testBookLink = 'http://clipart-library.com/newimages/clip-art-books-15.png'
const testBookImg2 = testBookImg1 ?? testBookLink
console.log('testBookImg2', testBookImg2)
// the same, just a suffix added, so it doesn't crash:
const obj2_undefined = {
items: [{
volumeInfo: {}
}]
}
const testBookImg1_undefined = obj2_undefined?.items[0]?.volumeInfo?.imageLinks?.thumbnail
const testBookLink_undefined = 'http://clipart-library.com/newimages/clip-art-books-15.png'
const testBookImg2_undefined = testBookImg1_undefined ?? testBookLink_undefined
console.log('testBookImg2_undefined', testBookImg2_undefined)