Filtrando películas por categoría
Clase 11 de 17 • Curso de API REST con Javascript: Ejemplos con APIs reales
Contenido del curso
Clase 11 de 17 • Curso de API REST con Javascript: Ejemplos con APIs reales
Contenido del curso
Juan Sebastian Espínola
Federico Ivan Llano
Elber Liebermen
Andres Chavez
Juan Castro
Andres Chavez
Ramiro Godoy
Lautaro Strappazzon
Lautaro Strappazzon
Raycris Maldonado
fabio andres zamora osorio
Juan Castro
Jose Castillo
Fernando Yutiz
VICTOR CAUDILLO
Donovan RM
Sabad Josue Perez Rodriguez
Daniela Stornelli
Antonio Rafael González Ferrer
Pablo Humberto Arriola Agudelo
Edgardo Andres Vargas Saenz
Pablo Humberto Arriola Agudelo
Miguel Enrique Velásquez Millán
Diego Eduardo Téllez Contreras
Omer José Hernández Ramones
Donovan RM
Yangetze González
JOSE RANGEL
Christian Velázquez
Jose Angel Morales Gonzalez
Eduardo Peña Ramos
¿Qué opinan de esta solución? .
Muy buena tu solucion, y yo pensando en que iba a necesitar usar clases, pero claro con la funcion y enviando parametros se soluciona. 👏
Wow muy interesante tu solución, me gustó mucho 😃
No sé si más adelante lo corrige el profe, pero al momento de entrar en una categoría que contiene un espacio en su título nos encontramos esto:
Pero pues lo podemos solucionar con un simple replace:p
Buen ojo ahí. ¿Sabes por qué aparece ese %20 en vez de un espacio? ¿Habrá alguna otra conversión o caso raro que debamos evaluar para solucionar?
Encontré que usualmente un % seguido de dos números quieren decir que un string fue codificado para formar parte de un URI, por cuestiones de evitar caracteres raros.
Se recomienda usar:
Para que la página inicie arriba y no en el footer, agregar en la función categoriesPage() el siguiente código:
window.scroll(0,0);
Para solucionar el segundo reto (ahorrarnos líneas de código para una funcionalidad que se repite), lo que hice fue hacer una función llamada printMoviePosters, que recibe como paråmetros el objeto movies, y la sección en la que corresponde. Luego, cada función que la necesite la llamará, pasándole los parámetros correspondientes:
const printMoviePosters = (movies, section) => { section.innerHTML = ""; movies.forEach(movie => { const movieContainer = document.createElement('div'); movieContainer.classList.add('movie-container'); const movieImg = document.createElement('img'); movieImg.classList.add('movie-img'); movieImg.setAttribute('alt', movie.title); movieImg.setAttribute( 'src', `${POSTER_300W_URL}${movie.poster_path}` ); movieContainer.appendChild(movieImg); section.appendChild(movieContainer); }); } const getTrendingMoviesPreview = async () => { const { data } = await api('/trending/movie/day'); const movies = data.results; printMoviePosters(movies, trendingMoviesPreviewList); } const getMoviesByCategory = async (categoryId) => { const { data } = await api('/discover/movie', { params: { with_genres: categoryId, }, } ); const movies = data.results; printMoviePosters(movies, genericSection); }
En cuanto al reto del problema del scroll, creo haberlo solucionado agregando el scrollTo(0,0) en la función que se dispara al hacer click en el botón categoryTitle:
categoryTitle.addEventListener('click', () => { location.hash = `#category=${category.id}-${category.name}`; window.scrollTo(0, 0); })
POSTER_300W_URL simplemente es una variable en la que guardé la url que nos permite imprimir los pósters con una ancho de 300:
const POSTER_300W_URL = 'https://image.tmdb.org/t/p/w300';
Muy buen aporte, tambien lo pense de esa manera, sacar una funcion a parte. me resulto de mucha ayuda lo del scroll
Segun lo que entendi en esta clase el hash no solo sirve para la navegacion entre paginas sino que tambien sirve para almacenar en dicho hash datos traidos de un endpoint de la api, de esta forma al leer el hash se obtiene el dato requerido para hacer peticiones a otros endpoints de la api. ¿estoy en lo correcto o no?
Correcto!
Investigue el scrollTo(cord-x, cord-y);
con este método solucionamos el problema del scroll que aparece hasta abajo, solo debemos insertar el código en la función de navegación de categoriesPage:
window.scrollTo(0,0);
de este modo se ubicara al inicio de la pagina.
Hay otro detalle que cuando hacemos un refresh (f5), o usamos el botón de ir a atras en el navegador, si tenemos el scroll hasta abajo este no cambia su posición.
Un comportamiento optimo seria que si actualizamos la pagina o le damos hacia atras o adelante, este se ubique al inicio de la pagina, para solucionar esto también podemos usar el scrollTo anclado a un evento.
window.onbeforeunload = () => { scrollTo(0,0); }
Este bloque de código, va en el main.js.. ahora cada vez que actualicemos o le demos hacia atrás, la vista de la pagina se ubicara desde el inicio.
Se me ocurrió como solución alternativa para mostrar la categoría al usuario, colocarla como parte del titulo
document.title=`PlatziMovies ${category.name}`;
Que les parece?
Me parece una mejor opción sobre todo pq al tomar el valor de la url se podria alterar o mostrar signos raros, buena idea!!
Para evitar que Ponga en el Title los caracteres codificados % de espacio y acentuación se puede usar el:
decodeURIComponent()
en el innerHTML es decir: en el navigation.js
const [categ, categoryData] = location.hash.split('=');// ['#category','id-name'] const [categoryId, categoryName] = categoryData.split('-'); headerCategoryTitle.innerHTML= decodeURIComponent(categoryName); getMoviesByCategory(categoryId);
Para poner en español las respuestas de la api (Categorías y algunos posters de Series y Películas) usando Axios, definimos en los parametros de la solicitud el parametro 'language' : 'es'. .
const api = axios.create({ baseURL: 'https://api.themoviedb.org/3', headers: { 'Content-Type': 'application/json;charset=utf-8' }, params:{ 'api_key': API_KEY, 'language': 'es' //para que las categorias lleguen en español } })
me pasa que las tildes no las reconoce y me pone varios simbolos en su lugar
Esta fue mi solución para re utilizar el código de las películas:
async function getTrendingMoviesPreview() { body.scrollTop = 0 const { data } = await api(URL_TrendingMovies) const movies = data.results trendingMoviesPreviewList.innerHTML = '' renderMovies(trendingMoviesPreviewList, movies) } async function getMoviesByCategory(id) { const { data } = await api(URL_DiscoverMovie,{ params: { with_genres: id } }) const movies = data.results genericSection.innerHTML = '' renderMovies(genericSection, movies) } function renderMovies(mainSection, movies) { movies.forEach(movie => { const movieContainer = document.createElement('div') movieContainer.classList.add('movie-container') const movieImg = document.createElement('img') movieImg.classList.add('movie-img') movieImg.setAttribute('alt', movie.title) movieImg.setAttribute('src', `https://image.tmdb.org/t/p/w300${movie.poster_path}`) movieContainer.appendChild(movieImg) mainSection.appendChild(movieContainer) }) }
También corregí el detalle de los espacios en el títulos de las categorías:
function categoriesPage() { // console.log('Category!!') headerSection.classList.remove('header-container--long') headerSection.style.background = '' arrowBtn.classList.remove('inactive') arrowBtn.classList.remove('header-arrow--white') headerTitle.classList.add('inactive') headerCategoryTitle.classList.remove('inactive') searchForm.classList.add('inactive') trendingPreviewSection.classList.add('inactive') categoriesPreviewSection.classList.add('inactive') genericSection.classList.remove('inactive') movieDetailSection.classList.add('inactive') const [_ , categoryData] = location.hash.split('=') const [categoryId, categoryName] = categoryData.split('-') headerCategoryTitle.innerText = categoryName.replace('_', ' ') getMoviesByCategory(categoryId) }
 que en caso de no pasarle ningún parámetro elimina los hijos de un contenedor
function createMovies(movies, container){ let moviesList = []; container.replaceChildren(); movies.forEach( movie => { const movieContainer = document.createElement('div'); const movieImg = document.createElement('img'); movieContainer.classList.add('movie-container'); movieImg.classList.add('movie-img'); movieImg.setAttribute('alt', movie.title); movieImg.setAttribute('src', 'https://image.tmdb.org/t/p/w300/'+movie.poster_path); movieContainer.append(movieImg); moviesList.push(movieContainer); }); container.append(...moviesList); }
Y para los que han usado la funcion insertAdjacentHTML en el main. esta es una propuesta que funciona para enviar el hash del evento click:
categories.forEach(category => { const categoryId = category.id; const categoryName = category.name; //const encodedCategoryName = encodeURIComponent(categoryName); const hash = `#category=${categoryId}-${categoryName}`; categoriesPreviewList.insertAdjacentHTML('beforeend', ` <div class="category-container"> <h3 id="id${categoryId}" class="category-title">${categoryName}</h4> </div> `); const categoryTitle = document.querySelector(`#id${categoryId}`); categoryTitle.addEventListener('click', () => { location.hash = hash; }); });
Like si antes de llegar a esta clase ya habías desarrollado esta funcionalidad jajajaja.
Para evitarnos escribir el mismo código que renderice cada película (ya sea en el home o en la lista de películas por categoría), podríamos crear una función al cual se le pase dos parámetros, la data y el nodo donde se deben 'pintar'. . Puede ser algo más o menos así: .
function renderMoviesHtml(data, node){ data.forEach(movie => { const movieContainer = document.createElement('div'); movieContainer.classList.add('movie-container'); const movieImg = document.createElement('img'); movieImg.classList.add('movie-img'); movieImg.setAttribute('alt', movie.title); movieImg.setAttribute('src', `https://image.tmdb.org/t/p/w300/${movie.poster_path}`); movieContainer.appendChild(movieImg); node.appendChild(movieContainer) }); }
. Luego sería llamar esta función pasándole los respectivos argumentos y ahorramos varias líneas de código.
Una clse genial!! Creo que, para los que van comenzando pueden volver a repasae éste curso (proyecto) para un curso como "webpack". Además, como el de "Single Page Application".
Esta era mi solución:
const index = window.location.hash.indexOf('=') const index2 = window.location.hash.indexOf('-') const query = window.location.hash.substring(index + 1, index2)
es muy forzada
Solución al reto de cargar la página desde el top: basta con poner esta línea de código en nuestra función:
window.scrollTo(0, 0);
Ejemplo:
Y para el que quiera profundizar más, esta es su documentación: https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollTop
Saludos! :D