Book Search dynamic web application - javascript

This web program name is Book search by using html, css, and javascript. In this code how can i do http GET request to searchInput element and how can i put bootstrap spinner to html searchInput element. Please explain and help me. According to this code two steps are not getting, the two steps are
When a value is entered in the HTML input element with id searchInput, x books option is selected in the HTML select element with id selectDisplayCount, an HTTP GET request with a valid url parameters title and maxResults should be made
When a value is entered in the HTML input element with id searchInput, x books option is selected in the HTML select element with id selectDisplayCount, an HTTP GET request should be made to fetch and display x book items
let searchInputEl = document.getElementById("searchInput");
let spinnerEl = document.getElementById("spinner");
let searchresultsEl = document.getElementById("searchResults");
let selectDisplayCountEl = document.getElementById("selectDisplayCount");
let bookcount = selectDisplayCountEl.value;
let formData = {
count: "10 Books",
};
function createAndAppendSearchResult(result) {
let {
title,
imageLink,
author
} = result;
let resultItemEl = document.createElement("div");
resultItemEl.classList.add("country-card", "col-6", "mr-auto", "ml-auto", "d-flex", "flex-column");
searchresultsEl.appendChild(resultItemEl);
let imageEl = document.createElement("img");
imageEl.classList.add("image", "mt-auto", "mb-auto");
imageEl.src = imageLink;
resultItemEl.appendChild(imageEl);
let authorEl = document.createElement("p");
authorEl.classList.add("author-name");
authorEl.textContent = author;
resultItemEl.appendChild(authorEl);
}
function displaySearchResults(searchresult) {
for (let result of searchresult) {
let titleName = result.title;
if (titleName.includes(searchInputEl.value)) {
createAndAppendSearchResult(result);
} else {
searchInputEl.textontent = "No reuslts found";
}
}
}
function searchBook(event) {
if (event.key === "Enter") {
let url = "https://apis.ccbp.in/book-store?title=kalam&maxResults=30" + bookcount;
let options = {
method: "GET"
};
spinnerEl.classList.remove("d-none");
searchresultsEl.classList.add("d-none");
fetch(url, options)
.then(function(response) {
return response.json();
})
.then(function(jsonData) {
searchresultsEl.classList.remove("d-none");
spinnerEl.classList.add("d-none");
console.log(jsonData)
let {
search_results
} = jsonData;
console.log(JSON.stringify(jsonData))
displaySearchResults(jsonData.search_results);
});
}
}
selectDisplayCountEl.addEventListener("change", function(event) {
formData.count = event.target.value;
console.log(formData.count);
});
searchInputEl.addEventListener("keydown", searchBook);

When the HTTP GET request is successful, then the searchResults element should consist of HTML image elements with src attribute value as the value of key 'imageLink' and HTML paragraph elements with text content as the value of key 'author' from HTTP response

Related

mapped button info is out of bounds

function AddDocument(Name, TTid) {
auth.onAuthStateChanged(user => {
if(user) {
const colUser = collection(fsinfo, 'User');
// goes to database colelction "user"
const colUser2 = doc(colUser, user.uid);
// goes to the document in colUser named "one"
const colUser3 = collection(colUser2, 'MoviesLiked');
whenSignedIn.hidden = false;
whenSignedOut.hidden = true;
setDoc(doc(colUser3, Name), {
movieliked: TTid,
})
}
else {
whenSignedIn.hidden = true;
whenSignedOut.hidden = false;
//userDetails.innerHTML = '';
console.log( "while logged out" );
console.log("notloggedin");
}
})
};
// query can either be a title or a tt id
function searchMovie(query) {
const url = `https://imdb8.p.rapidapi.com/auto-complete?q=${query}`;
fetch(url, options)
.then(response => response.json())
.then(data => {
var outname = null;
var outdetail = null;
const movieList = document.querySelector('.movielist');
movieList.addEventListener('click', handleClick);
const list = data.d;
//array of list with data from the movie search
//data.d is the specific datas that is outputted from the api
//list is an array that holds that data
console.log(list)
// ^ will output what list holds
const html = list.map(obj => {
const name = obj.l; // holds the name of movie
outname = name;
const poster = obj.i.imageUrl; // holds the poster, i is the image
const detail = obj.id
outdetail = detail;
return `
<section class="movie">
<img src="${poster}"
width = "500"
height = "800"/>
<h2>${name}</h2>
<section class = "details">${detail}</section>
<button type="button">Movie Details</button>
</section>
`;
}).join('');
// Insert that HTML on to the movie list element
function handleClick(e) {
if (e.target.matches('button')) {
const details = e.target.previousElementSibling;
details.classList.toggle('show');
AddDocument(outname, outdetail);
}
}
movieList.insertAdjacentHTML('beforeend', html);
document.getElementById("errorMessage").innerHTML = "";
})
.catch((error) => {
document.getElementById("errorMessage").innerHTML = error;
});
I have a function that will take search to an API call and then load the info from the API to a list.
It should then output said each of said list using list.map(obj) and each item will have a name, poster, and a button attached to it.
Outside the map I have a function that will react when the button is pressed which will toggle and then load the details of the movie to a database in the AddDocument function. My issue is that I am not sure how to make it so that when the button is pressed AddDocument will add whichever obj.name is connected to the button.
Currently, AddDocument will only add the last item in the list and not the item that I pressed the button for.
I know that it is because the function is outside where the mapping is done, and thus the items that are held in outname, and outdetail are the last items that have been mapped. But I just can't figure out a way to make the button press add the correct document to the database.
(I really didn't want to ask this, but I had spent hours thinking and searching and couldn't seem to find a solution. Thank you for any form of feedback that there may be.)

How to attach Media to a Facebook Post using the API

I have followed the Facebook documentation to request access token and post to a Facebook Page.
Now, I wish to create a post and attach some photos to that post but Facebook is only posting the text body and not including the photo files.
Here is how I did it:
...
let mediaIds = [];
for (let photoUrl of photoUrls) {
let mediaUploadUrl = `https://graph.facebook.com/${pageId}/photos?url=${photoUrl}&access_token=${pageAccessToken}`;
let response = await axios.post(mediaUploadUrl);
let { id } = response.data;
if (id) {
mediaIds.push(id);
}
}
// Now that we have the mediaIds, let's attach them to the post as below:
let urlParams = new URLSearchParams();
urlParams.append("access_token", pageAccessToken);
urlParams.append("message", "Hello World");
let postUrl = `https://graph.facebook.com/${pageId}/feed`;
if (mediaIds.length > 0) {
for (let i = 0; i < mediaIds.length; i++) {
let mediaId = mediaIds[i];
let mediaIdObject = { media_fbid: mediaId };
urlParams.append(`attached_media[${i}]`, mediaIdObject);
}
}
try {
let { data } = await axios.post(postUrl, urlParams);
let postId = data.id;
} catch (e) {
done = false;
console.log(e); //An unknown error has occurred is the error message I keep getting
}
...
All I keep getting in return is
An unknown error has occurred
But if I go to the Facebook Page, I noticed the text body was posted but not the photo attachments.
Any ideas on fixing this would be really appreciated.
Appending an object to urlParams, as you do in
let mediaIdObject = { media_fbid: mediaId };
urlParams.append(`attached_media[${i}]`, mediaIdObject);
produces a URL parameter like
attached_media[0]=[object Object]
Use
urlParams.append(`attached_media[${i}]`, JSON.stringify(mediaIdObject));
instead.

I'm just starting with JS and I don't really understand how setTimeout works

I am developing a trivia page with a series of questions that I get through an API. When I give to start the game on the main page, I want to redirect me to a second page where the available categories will appear and when I click on them, the questions will appear with multiple answers.
Luckily I have managed to do all this, however, when I switch from one page to another I have not been able to get the categories to appear. They only appear if I am already on that page and I create a button to call the function that displays them.
I had thought of doing this function in this way so that it would switch me to the other page and then load the questions but I have not been able to get it to work.
Does anyone have a solution or know why it is not working?
function get_dataJson() {
let data_json = [];
fetch('https://opentdb.com/api.php?amount=10')
.then(response => response.json())
.then(data => data.results.forEach(element => {
data_json.push(element);
}));
return data_json;
}
let trivial_data = get_dataJson();
function startGame() {
let div_username = document.createElement("div");
let name = document.createElement("h2");
name.innerHTML = document.getElementById("name").value;
div_username.appendChild(name);
let categories = get_categories(trivial_data);
setTimeout("location.href='./game.html'", 1000);
setTimeout(function(){
document.getElementById('nav-game').appendChild(div_username);
show_categories(categories);
},2000);
}
function get_categories(trivial_data) {
let categories = [];
trivial_data.forEach(element => {
categories.push(element.category)
});
console.log(categories);
return categories;
}
function show_categories (categories) {
let div_categories = document.createElement("div");
let count = 0;
categories.forEach ( element => {
let element_category = document.createElement("button");
element_category.innerHTML = element;
element_category.id = count;
element_category.onclick = function() {
get_question(element_category.id);
};
count++;
div_categories.appendChild(element_category);
});
div_categories.className = 'categories';
document.getElementById("categories").appendChild(div_categories);
}
function get_question (pos) {
document.getElementById("categories").style.displays = 'none';
let question = document.createElement("h2");
question.innerHTML = trivial_data[pos].question;
let correct_answer = trivial_data[pos].correct_answer;
let incorrect_answers = trivial_data[pos].incorrect_answers;
let options = incorrect_answers.concat(correct_answer);
options = options.sort();
let div_choices = document.createElement("div");
options.forEach(element => {
let choice = document.createElement('button');
choice.innerHTML = element;
choice.id = 'true' ? element == correct_answer : 'false';
div_choices.appendChild(choice);
});
div_choices.className = 'answers';
document.getElementById("questions").appendChild(question);
document.getElementById("questions").appendChild(div_choices);
}
The first thing you should do is make sure you understand how to use fetch to get data asynchronously
async function get_dataJson() {
const response = await fetch('https://opentdb.com/api.php?amount=10');
const json = await response.json();
return json.results;
}
(async function(){
const trivial_data = await get_dataJson();
console.log(trivial_data);
})()
Then, rather than changing page, just stay on the same page and add/remove/hide elements as necessary - it looks like you have that bit sorted.

How to fetch and display a specific index in a JSON file using a Javascript loop

I am currently using fetch in javascript to obtain information from another site into my own. The issue I am having is, I am using a loop to display all of the indexes of the JSON file into my site. I actually want to get specific indexes to show, not all of them, for example, index 2,4 and 6.
Here is my code so far:
window.addEventListener("load", (event)=>{
const requestURL = 'https://byui-cit230.github.io/weather/data/towndata.json';
fetch(requestURL)
.then(function (response) {
return response.json();
})
.then(function (jsonObject) {
const towns = jsonObject['towns'];
for (let i = 0; i < towns.length; i++ ) {
let towninfo = document.createElement('section');
let townname = document.createElement('h2');
townname.textContent = towns[i].name;
towninfo.appendChild(townname);
document.querySelector('div.weathertowns').appendChild(towninfo);
}
});
})
This displays all of the towns in reference, but I only want to display the title of 3 specific ones. Any suggestions on how to proceed with this?
something like that
window.addEventListener("load", (event)=>
{
const requestURL = 'https://byui-cit230.github.io/weather/data/towndata.json'
, divWeathertowns = document.querySelector('div.weathertowns')
;
fetch(requestURL)
.then( response=>response.json() )
.then( jsonObject=>
{
const towns = jsonObject['towns']
;
for ( let i of [2,4,6] )
{
let towninfo = document.createElement('section')
, townname = document.createElement('h2')
;
townname.textContent = towns[i].name;
towninfo.appendChild(townname);
divWeathertowns.appendChild(towninfo);
}
});
})
<div class="weathertowns"></div>

Library Project - Updating the object when book is removed

Problem:
When the user creates a book, the information that is in the input fields will be displayed. There is a remove button that the user can click and it deletes the book. However, when I use filter() I'm just returning the book parameter, so what can I change about my deleteBook() to be able to delete a book? I don't want the UI to work but I just want the library array to update.
Repl: https://repl.it/#antgotfan/library
What I've tried:
I've tried manipulating the document and whenever the user clicked on the remove then it would be deleted but not update the object to show that it was actually deleted
// Variables
const addBook = document.querySelector("#add");
let library = [];
// Event Listeners
addBook.addEventListener("click", render);
document.addEventListener("click", deleteBook);
// Constructor
function Book(title, author, pages, isRead) {
this.title = title;
this.author = author;
this.pages = pages;
this.isRead = isRead;
}
// Prototypes
Book.prototype.toggleIsRead = function() {
if (this.isRead == "Read") {
this.isRead = "Not read";
} else {
this.isRead = "Read";
}
}
function deleteBook(event) {
if (event.target.id == "remove") {
library.filter(book => {
return book;
});
}
}
// Functions
function addBookToLibrary() {
let authorOfBook = document.querySelector("#author").value;
let bookTitle = document.querySelector("#book-title").value;
let numberOfPages = document.querySelector("#pages").value;
let status = document.querySelector("#isRead").value;
let newBook = new Book(bookTitle, authorOfBook, numberOfPages, status);
library.push(newBook);
return newBook;
}
function updateStatus() {
}
function emptyInputs() {
const inputs = Array.from(document.querySelectorAll("input"));
inputs.forEach(input => input.value = "");
}
function render() {
addBookToLibrary();
emptyInputs();
let newBook = library[library.length - 1];
let table = document.querySelector("table");
let createTr = document.createElement("tr");
table.appendChild(createTr);
createTr.innerHTML = `<td>${newBook.title}</td>
<td>${newBook.author}</td>
<td>${newBook.pages}</td>
<td><button class="table-buttons" id="not-read">${newBook.isRead}</button></td>
<td><button class="table-buttons" id="remove">Delete</button></td>`;
}
Error messages:
No errors but just not having an updated object to show what was kept or deleted.
Since the books are in an array you can use a function that takes the book properties like author, title etc
and then uses that info to find the book in the array and delete it.
let books = [{ title: "book1" }, { title: "book2" }];
console.log(books);
deleteBook("book2");
console.log(books);
function deleteBook(title) {
let i = books.findIndex(b => b.title == title);
books.splice(i, 1);
}
//Outputs
[ { title: 'book1' }, { title: 'book2' } ] //before delete called
[ { title: 'book1' } ] //after delete called
This soloution worked for me:
function deleteBook(event) {
if (event.target.id == "remove") {
const table = document.querySelector('table');
const tr = event.target.parentNode.parentNode;
table.removeChild(tr);
}
}
Basically, you grab the table and then remove the child node that had the event fired on it.
You can grab the table using the querySelector() function, and you may want to consider giving that table a unique id or something down the line.
const table = document.querySelector('table');
Then, you take the target of the event, which is the <button> element, and get it's grandparent by calling parentNode twice. The first parent is the <td> element, the next one is the <tr> element, which is what we want to remove from the table.
const tr = event.target.parentNode.parentNode;
Finally, you can call removeChild() on the <table> element and have it remove the row that the button was pushed from.
table.removeChild(tr);

Categories

Resources