Lautaro Strappazzon
Lautaro Strappazzon
Alejandro Forero Vanegas
Rubén Cuello
Jorge Sandoval
Juan Sebastian Aparicio Ordoñez
Miguel Enrique Velásquez Millán
Rubén Cuello
Juan Castro
ProfesorAxel Enrique Galeed Gutierrez
Nicolás Felipe Pinto Vega
Carlos Romero
Luis Paredes
CRISTIAN DARIO AGUDELO PORRAS
Matias Martel
Fabio Escobar
Bramucci Candela
César Augusto Cortés Labrada
Oscar Santiago Lara Escobar
Carlos Rodríguez
Juan Diego Prieto Rodríguez
Ricardo Daniel Baró Soto
Abigail Nahomi Chávez Lozano
Ricardo Alfonso Chavez Vilcapoma
Para implementar el infine scrolling en todas las secciones, lo que hice fue lo siguiente:
async function getPaginatedMovies( endPoint, { categoryId, query } = {}, ) { const { scrollTop, scrollHeight, clientHeight } = document.documentElement; const scrollAtBottom = (scrollTop + clientHeight) >= (scrollHeight - 15); const pageIsNotMax = page < maxPage; if (scrollAtBottom && pageIsNotMax) { page++; const { data } = await api(endPoint, { params: { page, with_genres: categoryId, query, }, }); const movies = data.results; printMoviePosters(movies, genericSection, true); } }
function getPaginatedTrendingMovies() { getPaginatedMovies('/trending/movie/day'); } function getPaginatedMoviesByCategory() { const [_, categoryData] = location.hash.split('='); const [categoryId] = categoryData.split('-'); getPaginatedMovies('/discover/movie', {categoryId}); } function getPaginatedMoviesBySearch() { const [_, undecodedQuery] = location.hash.split('='); const query = decodeURI(undecodedQuery); getPaginatedMovies('/search/movie', {undefined, query}); }
function searchPage () { // función recortada infiniteScroll = getPaginatedMoviesBySearch; } function categoriesPage () { // función recortada infiniteScroll = getPaginatedMoviesByCategory; } function trendsPage () { // función recortada infiniteScroll = getPaginatedTrendingMovies; }
page = 1; infiniteScroll = getPaginatedTrendingMovies;
++De esta forma logré que las 3 secciones tengan infinite scrolling, intentando mantenerme DRY++
*Cualquier error o correción, siempre súper bienvenido!
Además, agregué un mensaje cada vez que se queda sin resultados el scroll:
Para hacer esto, creé (en index.html) una nueva sección debajo de genericList, inactiva por defecto:
<section id="max-page" class="inactive"> <h3> We're sorry but there's no more matches for your search 😕 </h3> </section>
En nodes.js definí la variable:
const maxPageReached = $('#max-page');
En la función global de paginación agregué un else if que chequeara que se llegó al final del scroll y que no hay más páginas de resultados:
async function getPaginatedMovies( endPoint, { categoryId, query } = {}, ) { // función recortada } else if (scrollAtBottom && !pageIsNotMax) { maxPageReached.classList.remove('inactive'); // removemos el inactive y de esta forma se muestra el mensaje }; }
Finalmente, en navigation.js, a la función de cada página volví a ponerle inactive a la magPageReached para que no aparezca en caso de que se active en algún momento y se mantenga en las otras secciones, como en el siguiente ejemplo:
Agregué algunos estilos para que se vea más o menos decente (sé que se puede mejorar):
#max-page h3 { width: 70%; margin: 0 auto; text-align: center; }
Alguien encontró una mejor forma de hacerlo?
Genial! Me ayudó tu código para reparar un bug que tenía hace más de una semana. ¡Gracias!
Yo resolví el problema obteniendo el id desde el hash
location.hash.split('=')[1].split('-')[0]
cree una funcion paga searMovies y una funcion para moviesByCategory y desde ahi antes de hacer la peticion tome del hash el id que necesite,
const [_, urlId, urlName] = location.hash.split("=");
async function getPageCategoryMovies() { const {scrollTop, clientHeight, scrollHeight} = document.documentElement; const scrollIsButton = (scrollTop + clientHeight) >= (scrollHeight - 25); const [_, urlId, urlName] = location.hash.split("="); const limitMaxPage = page < limitPage; if (scrollIsButton && limitMaxPage) { page++; const { data } = await api('discover/movie', { params : { with_genres : urlId, page, }, }); const movies = data.results; loadImage(genericSection, movies, {lazy: true, clear: false,}); } }
y lo mismo para search
En mi caso hice una función única para manejar todos los botones de carga infinita, de search, de categories y de trending.
/** * Maneja toda la lógica de los botones de carga. * * @param {string} url La url del endpoint. * @param {string} currentPage La página actual que se recibe de la respuesta del endpoint. * @param {string} totalPages La cantidad total de páginas que se recibe del endpoint. * @param {string} container El contenedor principal o el section que está visible. * @param {object} extraParams Parámetros extra para mandar a la consulta. */ function loadMoreMoviesBtnHandler( url, currentPage, totalPages, container, extraParams ) { // Revisa si hay paginas para cargar. if (currentPage < totalPages) { // Crea el boton de carga y lo inserta unicamente en la seccion actual. const loadMoreBtn = document.createElement('button'); loadMoreBtn.classList.add('loadMore'); loadMoreBtn.innerText = 'Load More'; loadMoreBtn.setAttribute('data-page', currentPage); // Agrega un observador al boton para disparar un evento de clic cuando sea visible. loadMoreMoviesObserver.observe(loadMoreBtn); container.appendChild(loadMoreBtn); // Agrega un event listener al boton. loadMoreBtn.addEventListener('click', async () => { let newCurrentPage = parseInt(loadMoreBtn.getAttribute('data-page')) + 1; const {data} = await api(url, { params: { page: newCurrentPage, ...extraParams }} ); createMoviesMarkup(data.results, container, false); let lastNode = container.querySelector('.movie-container:last-child'); lastNode.parentNode.insertBefore(loadMoreBtn, lastNode.nextSibling); loadMoreBtn.setAttribute('data-page', newCurrentPage); }) } else { let loadMore = container.querySelectorAll('.loadMore'); if ( loadMore.length ) { loadMore[0].remove(); } } }
También creé un Observer en vez de un eventListener de scroll (me pareció mas eficiente)
let loadMoreMoviesObserver = new IntersectionObserver((loadMoreObjetcs) => { loadMoreObjetcs.forEach(loadMoreButton => { if (loadMoreButton.isIntersecting) { loadMoreButton.target.click(); } }) })
Y para llamar al handler lo hice así:
// Trending movies. async function getTrendingMovies() { const endPoint = '/trending/movie/day'; const {data} = await api(endPoint); const movies = data.results; createMoviesMarkup(movies, genericSection); loadMoreMoviesBtnHandler(endPoint, data.page, data.total_pages, genericSection); } // Search async function getMoviesBySearch(query) { const endPoint = '/search/movie'; const {data} = await api(endPoint, { params: { query, } }); const movies = data.results; createMoviesMarkup(movies, genericSection); loadMoreMoviesBtnHandler(endPoint, data.page, data.total_pages, genericSection, {query}); } // Categories async function getMoviesByCategory(id) { const endPoint = '/discover/movie'; const {data} = await api(endPoint, { params: { with_genres: id, } }); const movies = data.results; createMoviesMarkup(movies, genericSection); loadMoreMoviesBtnHandler(endPoint, data.page, data.total_pages, genericSection, {with_genres: id}); }
Cuando intenté implementar el infinite scrolling por mi cuenta (de una forma distinta a la del Profesor Juan), también pensé que una buena forma de aplicarlo para todas las demás secciones sería mediante clousures para que así individualmente cada sección "recuerde" o "guarde" la página actual en la que se encuentra . Sin embargo... Al final ni siquiera me molesté en intentarlo debido a que en realidad (a pesar de que las conozco) no sé cómo crear ni usar las clousures, je je je 😅.
·
Por lo tanto al final terminé implementando todo de forma la cual dejaré por aquí~ Probablemente no sea la forma más bonita ni óptima, pero al menos funciona, je je 👉👈.
·
En mi solución, modifiqué las funciones getTrendingMovies, getMoviesBySearch y getMoviesByCategory para que recibieran un parámetro extra: el número de la página. De esta forma, cada vez que se llegue al final del scroll, simplemente se vuelve a llamar a las mismas funciones pero pasándoles la página que se supone deben cargar.
// Get Trending Movies. async function getTrendingMovies(page = 1) { try { thereAreSomeRequestsInProcess = true; const isTheFirstLoad = (page === 1); if (isTheFirstLoad) { genericSection.innerHTML = ""; showMoviesLoadingScreen(genericSection); const { data } = await api(`trending/movie/day?page=${page}`); const movies = data.results; currentLimitPagination = data.total_pages; createMovies(movies, genericSection, isTheFirstLoad); console.group("Respuestas del Servidor (GET Trending Movies)"); console.log(data); console.groupEnd(); } else { if (page <= currentLimitPagination) { showInfiniteScrollingMoviesLoadingScreen(genericSection); currentPagination = page; const { data } = await api(`trending/movie/day?page=${page}`); const movies = data.results; currentLimitPagination = data.total_pages; createMovies(movies, genericSection, isTheFirstLoad); if (page === currentLimitPagination) showInfiniteScrollingEndMessage(genericSection); console.group("Respuestas del Servidor (GET Trending Movies by Scrolling)"); console.log(data); console.groupEnd(); } } thereAreSomeRequestsInProcess = false; } catch (error) { console.group("%cError (GET Trending Movies)", consoleErrorMessageStyle); console.error(error); console.groupEnd(); alert("Ocurrió un Error en el GET de las Películas en Tendencia."); } }
· ¿Y quién se encarga de pasar el número de la página a cargar? Una función ubicada en el ++navigation.js++ donde también están las variables goblales que indican la página actual de la sección y el límite máximo de la misma.
// Infinite Scrolling let currentPagination = 1; // Página Actual de la Sección let currentLimitPagination = null; // Límite de la Paginación Actual let thereAreSomeRequestsInProcess = false; document.addEventListener("scroll", loadMoreMoviesByInfiniteScrolling); function loadMoreMoviesByInfiniteScrolling() { const {scrollTop, scrollHeight, clientHeight} = document.documentElement; const endOfScrollReached = (scrollTop+clientHeight) >= (scrollHeight-100); if (endOfScrollReached && !thereAreSomeRequestsInProcess) { thereAreSomeRequestsInProcess = true; if (location.hash === "#trends") { console.log(`Se llegó al final del scroll de la página ${currentPagination} en las tendencias.`); getTrendingMovies(currentPagination+1); } if (location.hash.startsWith("#search=")) { console.log(`Se llegó al final del scroll de la página ${currentPagination} en la búsqueda.`); const searchedTerm = location.hash.split("=")[1].trim(); getMoviesBySearch(searchedTerm, currentPagination+1); } if (location.hash.startsWith("#category=")) { console.log(`Se llegó al final del scroll de la página ${currentPagination} en la categoría.`); const categoryId = location.hash.split("=")[1].split("-")[0]; getMoviesByCategory(categoryId, currentPagination+1); } } }
Acabo de notar que el valor de page crece demasiado tras un pequeño scroll. Yo creí que iba a incrementar de a 1 tras mostrar 20 nuevos resultados, pero no es así. No encuentro el error. A alguien más le pasa?
Disculpa, Ruben. No entiendo tu pregunta. ¿Cuál es el error?
Hola, @RubenSH. :D
Sé a cuál error te refieres, se supone que a medida que vamos haciendo scroll vamos cargando una página de la API a la vez, pero, en cambio, cargan más de una.
A mi parecer es un "error" entre comillas, ya que no afecta el funcionamiento del proyecto. Quizás baja un poco la performance de la web, pero no lo sé aún ya que no lo he testeado.
De todas formas puedes solucionarlo con una función que retrase o haga una pequeña parada antes de continuar con su ejecución. Yo lo hice con una promesa, te dejó el código.
const waitATime = () => { return new Promise((result) => { setTimeout(() => result, 2000); }); };
Saludos.
Yo creé una función de paginación general que se puede usar con cualquier sección, y esta va a recibir los paramatros que necesite para crear el Infinite Scrolling. Para usarla simplemente se tiene que invocar dentro de la función inicial de cada sección.
//Esta funcion se usa para mostrar mas resultados de peliculas para las vistas de tendencias, categorias y búsqueda. async function getPaginatedMovies({ url, params, page, container } = {}) { const { data } = await api(url, { params:{ ...params, page, } }); //se desestructura la respuesta de api para obtener los datos de una vez const movies = data.results; //movies es el objeto de peliculas según los datos iniciales. tiene una total de 20 elementos. console.log(movies); //se llama a la funcion createMovies para visualizar las peliculas según los datos iniciales createMovies({ movies, container, movieModificator: '--small', clean: false, }) }
Ejemplo de implementación:
async function getMovieBySearch(query){ let page = 1; //Esta variable controla la páginación de la API. //se hace la solicitud GET con la instancia de AXIOS para traer el objeto de peliculas según la búsqueda del usuario. const { data } = await api(`search/movie`,{ params:{ 'language': 'en-US', query, } }); //se desestructura la respuesta de api para obtener los datos de una vez const movies = data.results; //movies es el objeto de peliculas según la categoria. tiene una total de 20 elementos. //se llama a la funcion createMovies para visualizar las peliculas segun la búsqueda del usuario. createMovies({ movies, container: genericMovieList, movieModificator: "--small", }) //Cargar mas contenido //primero se valida que no exista una funcion infinite scrolling, y si si lo hay se elimina. if(infiniteScrolling){ genericListSection.removeEventListener('scroll', infiniteScrolling); infiniteScrolling = undefined; console.log('test'); } //Se asigna la función especifíca de la sección al infinite scrolling. infiniteScrolling = () => { const isUserAtBottom = genericListSection.scrollTop + genericListSection.clientHeight >= genericListSection.scrollHeight - 5; //Se hace la validación si el usuario alcanzó el fondo de la pantalla if(isUserAtBottom){ page++; //Se suma uno a la página //Se invoca la función de paginación con los respectivos parametros de la sección. getPaginatedMovies({ url: 'search/movie', params: { 'language': 'en-US', query, }, page, container: genericMovieList, }) } } genericListSection.addEventListener('scroll', infiniteScrolling); }
Yo implemente la solucion de obtener los parametros, ya sea el ID o el query, a traves de location.hash. Exactamente como lo hicimos en navigation.js.
No se si sea lo mas optimo pero funciona.
yo resolvi el problema asi:
infiniteScroll = () => { getPaginatedMoviesBySearch(realQuery)}```
A mi parecer es menos complicado de lo que parece, ya que, al cargar la 1ra pagina de nuestra seccion (seach o category) con location.hash podemos tomar ese id o ese query para hacer la solucitud de la 2da pagina y de las sucesivas. Espero haber sido claro y que pueda servirle a alguien!!
En mi solucion me sali de la tangente sin querer al elegir como primer funcion para implementar el infinite scrolling aquella que maneja las peliculas recomendadas dentro de la seccion movieDetail y me encontre con una serie de complicaciones a resolver sobre la marcha: -La primera fue el hecho de que esta llamada a la API no debe utilizar la variable infiniteScrolling que definimos para los demas eventos de scroll debido a que trabaja con el scroll vertical de un contenedor y no con el scroll de la seccion visible en la que nos encontramos. -La segunda fue que comprendi que en la clase previa nunca establecimos un reset en la variable "page", por lo cual cada vez que la reutilizabamos en un ciclo de uso cotidiano de un usuario (entrar a una seccion, scrollear, salir, entrar a otra seccion, scrollear, etc) no arrancabamos desde la primer pagina disponible de la API, por lo que tuve que buscar el punto justo donde insertarle un reset sin que ello produzca problemas en el infinite scroll en si. -Y por ultimo me parecia muy poco comodo el hecho de tener que arrastrar el scroll del contenedor "manualmente" para cargar mas peliculas debido a que eso provocaba muchas veces que la funcion se ejecutara varias veces consecutivas sin darme posibilidad de corregir la posicion del scroll y de esa forma evitar las multiples (si bien esto es algo a corregir en futuros updates), por lo cual termine implementado otro eventListener que se encargar de proveernos el scroll vertical con la rueda del mouse, tal cual lo hacemos en otras secciones. A continuacion les dejo como quedaria el codigo:
Asi queda la navigation de la seccion movieDetails
function movieDetailsPage () { console.log("Movie!!") headerSection.classList.add('header-container--long'); //headerSection.style.background = ''; arrowBtn.classList.remove('inactive'); arrowBtn.classList.add('header-arrow--white'); headerTitle.classList.add('inactive'); headerCategoryTitle.classList.add('inactive'); searchForm.classList.add('inactive'); trendingPreviewSection.classList.add('inactive'); categoriesPreviewSection.classList.add('inactive'); genericSection.classList.add('inactive'); movieDetailSection.classList.remove('inactive'); const [_, movieId] = location.hash.split('=') // ["#movie", 'movieID'] getMovieDetailById(movieId); getRelatedMoviedById(movieId); //Aqui insertamos el reset de la pagina en esta funcion y en cualquier otra que haga uso del infiniteScroll page = 1; }
Los eventos a escuchar dentro del contenedor
relatedMoviesContainer.addEventListener('scroll', getPaginatedRelatedMoviesbyId) relatedMoviesContainer.addEventListener('wheel', scrollHorizontalContainer)
La funcion en si de llamada a la API
async function getPaginatedRelatedMoviesbyId() { const [_, movieId] = location.hash.split('=') const { scrollLeft, scrollWidth, clientWidth } = relatedMoviesContainer; const scrollIsEnd = (scrollLeft + clientWidth) >= (scrollWidth - 10); if (scrollIsEnd) { page++; const { data } = await api(urlSimilarMovies(movieId), { params: { page, } }); const similarMovies = data.results; if (similarMovies) { movieRender(similarMovies, relatedMoviesContainer, {lazyLoad: true, clean: false}); } } }
Y por ultimo la funcion de scrollVertical haciendo uso del mouse
function scrollHorizontalContainer (event) { // Se puede modificar la velocidad corrigiendo el decimal relatedMoviesContainer.scrollLeft += event.deltaY * 0.50; }
**Disclaimer Hice uso del endpoint similarMovies debido a que testee muchas peliculas que no sean del todo populares (o son antiguas, etc) y el endpoint de Recommendations normalmente se encuentra vacio y por lo tanto no util para el uso de nuestra app
Yo lo resolví pero el código es un desastre 😂
function infiniteScroll() { const scrollCond = document.documentElement.scrollTop + document.documentElement.clientHeight >= document.documentElement.scrollHeight; if (scrollCond && location.hash.startsWith("#trends")) { getTrendingMovies({ pag: pag, clear: false }); pag++; } if (scrollCond && location.hash.startsWith("#category=")) { const hashContent = location.hash; const idAndName = hashContent.slice(10); const idAndNameArray = idAndName.split("-"); const clicked_id = idAndNameArray[0]; const clicked_name = idAndNameArray[1].replace("%20", " "); getMoviesByCategory(clicked_id, clicked_name, pag, false); pag++; } if (scrollCond && location.hash.startsWith("#search=")) { const hashContent = location.hash; const [_, hashContentArray] = hashContent.split("="); const searchValue = hashContentArray.replaceAll("%20", " "); searchMovies(searchValue, { pag: pag, clear: false }); pag++; } }
Yo usé generators, me quedó así (está hecho rápido, todavía tengo que limpiar el código)
Navigation.js
function printMoviesByGenre() { genre.classList.add('active') const regex = /category=(\d+)-(.*)/ const genreData = regex.exec(location.hash) const id = genreData[1] const name = genreData[2] container = moviesByGenre getMoviesByGenre({ id, name }) const page = generator(1) document.onscroll = () => getPaginatedMovies('discover/movie', { with_genres: id }, page) }
Index.js
let maxPage let container let page = 1 function* generator(i) { while (true) { i++ yield i } } //... async function getPaginatedMovies(endpoint, params = {}, pageGenerator) { if (page > maxPage) return const { scrollTop, scrollHeight, clientHeight } = document.documentElement const scrollIsInBottom = scrollTop + clientHeight >= scrollHeight - 30 if (scrollIsInBottom) { page = pageGenerator.next().value params.page = page const { data } = await api(endpoint, { params, }) const movies = data.results createCards(movies, container, false) } }
Este es mi aporte, lo realicé antes de ver la clase 11 pero lo del passive no lo sabía XD, así que lo agregué después. En esta implementación creo el escuchador de scroll y mando a llamar la función inifityScroll en la cual se detectará en que vista se está parado y si se llegó al máximo scroll posible según cada condicional.
/* PAGINATION */ let page = 1; //Para las listas de trending y popular window.addEventListener("scroll", infinityScroll, {passive : false}); function infinityScroll(){ //Se extrae el máximo scroll segúnla vista actual const maxScroll = document.documentElement.scrollHeight - window.innerHeight; if( (maxScroll === window.scrollY) && (location.hash === "#more-trends")){ //Se aumenta la página page++; //Se manda a llamar la función de consulta trendingMovieViewMore(); } if( (maxScroll === window.scrollY) && (location.hash === "#more-popular")){ //Se aumenta la página page++; //Se manda a llamar la función de consulta popularMovieViewMore(); } if( (maxScroll === window.scrollY) && (location.hash.startsWith("#category"))){ //Se obtiene el id y nombre de categoría del hash usando split let [vista, categoryIdName] = location.hash.split("="); const [categoryId, categoryName] = categoryIdName.split("_"); //Se aumenta la página page++; //Se manda a llamar la función de consulta getMovieByCategory({name: categoryName, id:categoryId}); } if( (maxScroll === window.scrollY) && (location.hash.startsWith("#search"))){ //Se obtiene el nombre de búsqueda en el hash usando split y join let [vista, searchName] = location.hash.split("="); let query = searchName.split("-"); query = query.join(" "); //Se aumenta la página page++; //Se manda a llamar la función de consulta getMovieBySearch({query}); } }
En las funciones de consulta como trendingviewmore() etc; cada una tiene el parámetro de page dentro de la consulta de axios. Adicional se agregan las siguientes líneas para limpiar el contenedor de los posters de películas cuando es primera vez que se entra a dicha vista.
if(page <= 1) cardsContainer.innerHTML = "";
En navigation.js cada función de cambio de vista reiniciará la variable global "page" igualándola a 1, por ejemplo:
function trendingListPage(){ //Se quitan las vistas que no se deben mostrar y se deja sólo la deseada category.classList.add("d-none"); movieDetail.classList.add("d-none"); movieDetail.classList.add("d-md-none"); searching.classList.add("d-none"); trending.classList.add("d-none"); popular.classList.add("d-none"); popularList.classList.add("d-none"); searchBar.classList.add("d-none"); trendingList.classList.remove("d-none"); //Se reinicia la paginación page = 1; //Se manda a llamar las funciones generadoras de la información trendingMovieViewMore(); window.scrollTo(0, 0); }
aunque ese reinicio se puede hacer dentro de la función navigator también, ya que el objetivo es detectar un cambio de vista y reiniciar la paginación.
Como bonus cree un botón para hacer scroll hacia el top de las vistas ya que es dificil scrollear tanto luego de cargar mucha información y funciona con este código:
/* SCROLLTOP BUTTON */ const scrollTop = document.getElementById("scroll-button"); scrollTop.addEventListener("click", () =>{ window.scrollTo(0, 0); })
Mi solución para el Infinite Scrolling en páginas/secciones que reciben parámetros fue guardar estos valores en variables globales (como hicimos con maxPage) para luego poder acceder a ellos desde la función de Infinite Scrolling.
// navigation.js let page = 1; let maxPage; let infiniteScroll; let endpointInfiniteScroll; let infiniteScrollParams = { params: { page: 1, }, };
// main.js async function getMoviesByCategory(id) { endpointInfiniteScroll = "/discover/movie?with-genres="; infiniteScrollParams = { params: { with_genres: id, }, } const { data } = await api(endpointInfiniteScroll , infiniteScrollParams); maxPage = data.total_pages; createMovies(data.results, genericListMoviesPreview); }
//main.js async function getInfiniteMoviesList() { const { scrollTop, scrollHeight, clientHeight } = document.documentElement; const scrollIsBottom = (scrollTop + clientHeight >= scrollHeight - 15); const pageIsNotMax = (page < maxPage); if (scrollIsBottom && pageIsNotMax) { page++; infiniteScrollParams.params.page = page; const { data } = await api(endpointInfiniteScroll, infiniteScrollParams); createMovies(data.results, genericListMoviesPreview, { cleanSection: false, }); }
//navigation.js function navigator() { if(infiniteScroll){ window.removeEventListener('scroll', infiniteScroll, {passive: false}); infiniteScroll = undefined; page = 1; maxPage = 0; endpointInfiniteScroll = undefined; infiniteScrollParams = { params: { page: 1, }, }; } }
//navigation.js function categoriesPage() { // función recortada infiniteScroll = getInfiniteMoviesList; }
La solución es crear esas funciones reutiilizables para que pueda usarse con págiina 1 hasta la página n, también desde una función promesa podemos retornar un valor específico y cuando la usemos podemos catcharla con .then y allí hacer lo que queramos
const getTrendingMovies = async (page = 1) => { const dataUtil = {}; try { const { status, data } = await api.get(URL_TRENDING_RES('movie', 'day'), { params: { page }, }); ... dataUtil.total_pages = data.total_pages; } catch (error) { ... } return dataUtil; };
Para catcharla
const trendsPage = () => { ... getTrendingMovies().then((data) => { if (data.total_pages === 1) removeInfiniteScroll(); }); // Scroll infinito infiniteScroll = () => { if (scrollIsOnThreshold()) { getTrendingMovies(page).then((data) => { if (page >= data.total_pages) removeInfiniteScroll(); }); } }; };
. . Mi propuesta, commit actual: Click aquí
Yo lo resolvi de esta manera
Cree 2 variables por fuera de toda funcion
hice un refactor de pues estaba repitiendo codigo por cada peticion que se hacia
si ya se estan cargando datos, no se hacen mas peticiones, por eso coloco que si isLoading es true no genere otro llamado pero seguido, isLoading pasa de nuevo a true para hacer una nueva peticion
luego de cada forEach, page se incrementa a 1 para pasar a la siguiente pagina y isLoading pasa a false para que no este haciendo peticiones cada vez que se genere el scroll
en la funcion que cree para el scroll infinito
pongo parametros con un valor null para que sea llamado segun la funcion que se ejecute en cada vista del navigation y hago la validacion para generar el scroll
Finalmente hago el llamado en cada funcion por cada vista
Hola platzinautas 😁, la solución que encontre fue la siguiente:
1ro - definí una variable global infiniteScrollParams:
let ``infiniteScrollParams;
2do - luego la agregué en la validación de la funcion Navigator() para poder resetearla al cambiar de página:
if ``(infiniteScroll) {
window.removeEventListener('scroll', infiniteScroll, {passive: ``false``});
infiniteScroll = ``undefined``;
infiniteScrollParams = ``undefined``;
page = 1;
}
3ro - al final de cada una de mis funciones de navegación le asigne el valor de la función necesaria a la variable infiniteScroll, y de necesitar parametros se los asigno a la variable global infiniteScrollParams:
function ``searchPage() {
...
getMoviesBySearch(searchValue)
infiniteScrollParams = {searchValue: searchValue}
infiniteScroll = getPaginatedMoviesBySearch;
}
4to - luego en las funciones que necesitan parametros necesite hacer un destructuring para obtener el parametro necesario:
async function ``getPaginatedMoviesBySearch(params) {
``const ``{searchValue} = params
...
const ``{data} = ``await ``API('/search/movie', {
params: {
query: searchValue,
page: page
},
})}
5to - por ultimo agregué el evento:
window.addEventListener('scroll', handleInfiniteScroll, ``false``)
function ``handleInfiniteScroll() {
``try ``{
infiniteScroll(infiniteScrollParams)
} ``catch ``(error) {
}
}
Me tomo un buen tiempito , espero les sirva mi solucion.🥵
Para hacer a la función getPaginatedTrendingMovies un poco más general, use el evento 'onsroll', en vez de la variable infiniteScroll, asi podemos enviar parametros, que en este caso sería la url de la seccion en la se mande a llamar a la función.
document.onscroll = () => getPaginatedMovies('trending/movie/day')
document.onscroll = () => getPaginatedMovies('discover/movie')
async function getPaginatedMovies(url) { const { scrollTop, scrollHeight, clientHeight } = document.documentElement const scrollBottom = (scrollTop + clientHeight) >= (scrollHeight - 15) const pageIsNotIMax = page < maxPage if (scrollBottom && pageIsNotIMax) { page++ const {data} = await api(url, { params: { page } }); const movies = data.results; console.log(data); renderMovies(movies, genericListSection, {lazyLoad : true, clean: false}) } }
Para no tener problemas con los parámetros, lo que hice es que esas variables que recibe se hagan globales...por ejemplo en el caso de searchMovies:
De tal manera que así se puede aplicar la lógica del scroll infinito al igual que en trendingMovies