I have this song lyrics app, the problem is the spinner does not remove after the api fetch. it is like javascript does not detect the spinner already exist, but it exist! when I call the remove function.
If I remove the conditional:
if(spinnerHtml) {
spinnerHtml.remove();
};
and only leave this:
spinnerHtml.remove();
so I get this error: TypeError: Cannot read properties of null (reading 'remove').
const form = document.querySelector("#formulario-buscar");
const artistInput = document.querySelector("#artista");
const songInput = document.querySelector("#cancion");
const searchBtn = document.querySelector("#buscar");
const divMessages = document.querySelector("#mensajes");
const divResult = document.querySelector("#resultado");
const headingSong = document.querySelector("#song-name");
function spinner() {
const spinner = document.createElement("div");
spinner.classList.add('spinner');
spinner.setAttribute('id', 'spinner');
spinner.innerHTML = `
<div ></div>
<div ></div>
<div ></div>
<div ></div>
<div ></div>
`;
form.insertBefore(spinner, document.querySelector(".enviar"));
}
let spinnerExist = false;
form.addEventListener("submit", searchSong);
function searchSong(e) {
e.preventDefault();
//show spinner
if(spinnerExist === false) {
spinner();
spinnerExist = true;
};
//consult our API
const query = new API(artistInput.value, songInput.value)
query.consultApi();
}
const spinnerHtml = document.getElementById('spinner');
class API {
constructor(artist, song) {
this.artist = artist;
this.song = song;
}
async consultApi() {
const url = `https://api.lyrics.ovh/v1/${this.artist}/${this.song}`;
try {
const response = await fetch(url);
const result = await response.json();
// //when it found the lyrics it delete the spinner
if(spinnerHtml) {
spinnerHtml.remove();
};
const {lyrics} = result;
//here we assign the song lyrics to the DOM
divResult.textContent = lyrics;
headingSong.textContent = `Lyrics of ${this.song} from the artist ${this.artist}`;
} catch (error) {
console.log(error);
divMessages.textContent = error;
divMessages.classList.add("error");
setTimeout(() => {
divMessages.textContent = "";
divMessages.classList.remove("error");
}, 3000);
}
}
}
html{
min-height: 100%;
box-sizing: border-box;
}
*, *:before, *:after {
box-sizing: inherit;
}
body {
background-image: linear-gradient(to top, #1e3c72 0%, #1e3c72 1%, #2a5298 100%);
font-family: 'Montserrat', sans-serif;
min-height: 100%;
}
h1 {
font-weight: 400;
text-align: center;
}
h2 {
text-align: center;
}
.contenido {
background-color: white;
max-width: 1100px;
margin: 0 auto;
height: 100%;
padding: 20px;
}
@media (min-width:768px) {
.contenedor {
display: flex;
flex-wrap: wrap;
}
.contenedor > div {
flex: 1 0 50%;
}
}
.formulario-busqueda p {
text-align: center;
}
.formulario-busqueda span {
color: red;
}
.input {
margin-bottom: 1rem;
display: flex;
align-items: center;
}
.input label {
flex: 0 0 120px;
text-align: right;
margin-right: 1rem;
font-weight: 700;
text-transform: uppercase;
}
.input span {
color: red;
}
.input input[type="text"] {
height: 2.5rem;
padding: 1rem;
display: flex;
flex: 1;
}
.enviar {
text-align: center;
justify-content: center;
}
.input input[type="submit"]{
background-color: #6f86d6;
padding: .5rem 2rem;
color: white;
align-self: flex-end;
border:none;
transition: background-color .3s ease-in-out;
}
.input input[type="submit"]:hover {
cursor: pointer;
background-color: #384e9d;
}
.error {
padding: 1rem;
border: 1px solid red;
background-color: rgb(249, 121, 121);
color: white;
text-align: center;
}
#resultado {
white-space: pre-wrap;
padding: 2rem;
}
.spinner {
margin: 100px auto;
width: 50px;
height: 40px;
text-align: center;
font-size: 10px;
}
.spinner > div {
background-color: #333;
height: 100%;
width: 6px;
display: inline-block;
-webkit-animation: sk-stretchdelay 1.2s infinite ease-in-out;
animation: sk-stretchdelay 1.2s infinite ease-in-out;
}
.spinner .rect2 {
-webkit-animation-delay: -1.1s;
animation-delay: -1.1s;
}
.spinner .rect3 {
-webkit-animation-delay: -1.0s;
animation-delay: -1.0s;
}
.spinner .rect4 {
-webkit-animation-delay: -0.9s;
animation-delay: -0.9s;
}
.spinner .rect5 {
-webkit-animation-delay: -0.8s;
animation-delay: -0.8s;
}
@-webkit-keyframes sk-stretchdelay {
0%, 40%, 100% { -webkit-transform: scaleY(0.4) }
20% { -webkit-transform: scaleY(1.0) }
}
@keyframes sk-stretchdelay {
0%, 40%, 100% {
transform: scaleY(0.4);
-webkit-transform: scaleY(0.4);
} 20% {
transform: scaleY(1.0);
-webkit-transform: scaleY(1.0);
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Buscador de Letras - JSModerno</title>
<link rel="stylesheet" href="https://necolas.github.io/normalize.css/8.0.0/normalize.css">
<link href="https://fonts.googleapis.com/css?family=Montserrat:400,700,900" rel="stylesheet">
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<main id="contenido" >
<h1>Letras de Canciones</h1>
<div >
<div id="buscar" >
<h2>Búsqueda</h2>
<p>Busca por artista y nombre:</p>
<p><span> * </span>Obligatorio</p>
<form action="#" id="formulario-buscar">
<div >
<label for="artista">Artista: <span>*</span></label>
<input type="text" id="artista" placeholder="Artista">
</div>
<div >
<label for="cancion">Canción: <span>*</span></label>
<input type="text" id="cancion" placeholder="Nombre Canción">
</div>
<div >
<input type="submit" id= "buscar" value="Buscar">
</div>
</form>
</div>
<div >
<h2 id="song-name"></h2>
<div id="resultado"></div>
</div>
<div id="mensajes"></div>
</div>
</main>
<script src="js/app.js"></script>
</body>
</html>
CodePudding user response:
I think it's a bad practice to use out-of-scope variables inside classes. It looks like the variable spinnerHtml
is not accessible to the class function consultApi
. Try selecting the element inside the class function consultApi
with the query again.