No tienes acceso a esta clase

¡Continúa aprendiendo! Únete y comienza a potenciar tu carrera

¡Se acaba el precio especial! Aprende Inglés, AI, programación y más.

Antes: $249

Currency
$209
Suscríbete

Termina en:

1 Días
10 Hrs
33 Min
29 Seg

Retos: historial de navegación y página de tendencias

14/17
Recursos

Aportes 19

Preguntas 2

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad?

Quedé anonadado con la solución del historial de navegación con el objeto history y su método back() jajaja

Yo había creado un array el cual agregaba el location.hash cada vez que este cambiaba y cuando se le daba click al arrowBtn iba invocando los location.hash guardados para poder generar nuevamente la petición.

let historyArr = [];

arrowBtn.addEventListener("click", () => {
  if (historyArr.length > 1) {
    location.hash = historyArr[historyArr.length - 2];
    historyArr.splice(-2,2);
  } else {
    historyArr.pop();
    location.hash = "#home";
  }
});

function navigator() {
	  if(location.hash.startsWith("#trends") || location.hash.startsWith("#search=") || location.hash.startsWith("#movie=") || location.hash.startsWith("#category=")){
    historyArr.push(location.hash)
  }
}

Una solución supersencilla, podemos agregar una propiedad de carga en el window.history, es decir que cuando de cambie un hostname a otro o vengamos de otro hostname entonces podemos agregar ese href de carga inicial de la siguiente manera:

window.addEventListener(
    'DOMContentLoaded',
    () => {
        navigator();
        // Agregando un estado de carga inical
        window.history.pushState({ loadUrl: window.location.href }, null, '');
    },
    false,
);

.
Esa propiedad de carga de estado la he llamado loadUrl entonces si cargamos la aplicación desde su inicio el href no deberá contener ningún tipo de hash pero si venimos de youtube por ejemplo entonces el loadUrl nos dará todo el href se esa ruta de carga con todo y hash. Entonces si la ruta de carga inicial contiene el símbolo de hash (#) entonces nos mandará a la home desde el evento click del botón.

arrowBtn.addEventListener('click', () => {
    const stateLoad = window.history.state ? window.history.state.loadUrl : '';
    if (stateLoad.includes('#')) {
        window.location.hash = '';
    } else {
        window.history.back();
    }
});

Después de que neveguemos en diferentes rutas de la aplicación el window.history.state se borra dando como resultado null por eso es que la variable stateLoad regresamos un string vacío o lo que queremos realmente que es el window.history.state.loadUrl

Solucion al history.back()

Seguro más de uno habrá notado que la búsqueda funciona bastante bien salvo para los casos en los que el título tenga espacios en medio. Por ej no pueden buscar “Dragon Ball Z”, ya que no encontrará resultados.

Una solución simple a este problema es modificar el string que vamos a enviar a la consulta de manera de reemplazar los espacios (%20) del título por espacios de verdad:

La búsqueda funcionará sin problemas luego de eso 😄

Aqui mi solucion, espero a alguien le sirva!

let historial = []

arrowBtn.addEventListener('click', () => {
    historial.pop()
    if (historial.length > 0) {
        location.hash = '#search=' + historial[historial.length - 1]
    } else {
        location.hash = '#home'
    }
})

Puse el botón para volver atrás que recuerda la ultima posición del usuario con este método que se lo robé a alguien en los comentarios.

arrowBtn.addEventListener('click', () => {

    window.history.back()

});

Y por si el usuario quiere volver al home de un solo click, al clapper board le agregue el evento de volver al home

clapperboardHeader.addEventListener('click', () => {
    location.hash = '#home'
})

Por si a alguien le sirve de idea aquí esta como se ve 😃

Mi solución:

arrowBack.addEventListener('click', () => {
    // Get the URL of the previous page
    const previousUrl = document.referrer;

    // Check if the previous URL belongs to the same application
    if (previousUrl.includes(location.hostname)) {
        // If it does, go back to the previous URL
        history.back();
    } else {
        // If it doesn't belong to the same application, redirect to the application's home
        window.location.href = '/'; // Replace '/' with the URL of your home page
    }
});

Me puse a revisar el history en la consola y tiene un item que cambia y cuenta cuanto hemos avanzado, “history.length” cuando es 1, es la pestaña nueva vacia, cuando es 2 es la url que pegamos, y de ahí en adelante va a contar el historial, entonces sí ese valor es menor a 2, llévame al home, sí es mayor a 2 llevame al historial.
Creo que es la solución más sensilla que he visto puesto que solo se agrega el if.

Mi solución al reto:

	arrowBtn.addEventListener('click', () => {
  if (history.length > 1) {
    history.back()
  } else {
    location.hash = "#home"
  }

})

La parte del historial la hice de la siguiente forma:
Hice un arreglo en el que guardaría los valores del location.hash:

navigation.js

const historial = [];
searchFormBtn.addEventListener('click', () => {
    location.hash = `#search=${searchFormInput.value}`;
    historial.push(searchFormInput.value);
    navigation()
});

arrowBtn.addEventListener('click', () => {
    if(historial.length == 0){
        location.hash = '#home';
    }else if(historial.length == 1){
        location.hash = '#home';
        searchFormInput.value = '';
        searchFormInput.setAttribute('placeholder', 'Buscar');
        historial.pop();
    }else{
        location.hash = `#search=${historial[historial.length-2]}`;
        searchFormInput.value = '';
        searchFormInput.setAttribute('placeholder', historial[historial.length-2]);
        historial.pop();
    }
    navigation()
});

Y también implemente un setTimeout para que el usuario no tuviera que borrar lo que escribió en la búsqueda:

const searchPlaceholderWait = () => {
    setTimeout(() => {
        searchFormInput.value = '';
        searchFormInput.setAttribute('placeholder', historial[historial.length-1]);
    },2000);
}

Finalmente la funcion searchPlaceholderWait() la meti dentro de un condicional if, dentro de la funcion searchPage():

if(historial.length != 0){
        searchPlaceholderWait();
    }

Esta es mi solución:

Les comparto mi solución al reto del historial de navegación. 😄
Repositorio de GitHub.

const $$ = (id) => document.querySelectorAll(id);

const goBackButton = () => {
	const IS_HASH_HOME = location.hash !== '#home';
	const IS_LAST_NOT_HOME = ARRAY_HASHES.at(-1) !== '#home';

	if (IS_HASH_HOME) ARRAY_HASHES.pop();

	location.hash = (IS_LAST_NOT_HOME)
		? `${ARRAY_HASHES.at(-1)}`
		: '#home';
};

const addHash = () => {
	const IS_REPEAT = ARRAY_HASHES.some((hash) => location.hash === hash);

	if (!IS_REPEAT)ARRAY_HASHES.push(location.hash);
};

const BUTTONS_GO_BACK = Array.from($$('.header__arrow-left'));
const ARRAY_HASHES = [ '#home', location.hash ];

for (const BUTTON of BUTTONS_GO_BACK) {
	BUTTON.addEventListener('click', goBackButton);
}

window.addEventListener('hashchange', addHash, false);

Luego de renegar buscando informacion se me ocurrio esta manera

let canBack = 0
const navigator = () => {

  if (location.hash.startsWith('#trends')) {

    trends()

  } else if (location.hash.startsWith('#search=')) {

    const loc = location.hash
    const [_, search] = loc.split('=')

    search ? searchPage(search.replaceAll('%20', ' ')) : homePage()

  } else if (location.hash.startsWith('#movie=')) {

     moviePage()

  } else if (location.hash.startsWith('#category=')) {

    const loc = location.hash
    const [id, name] = loc.split('=')[1].split('-')
    categoryPage(id, name.replace('%20', ' '))

  }  else {

    homePage()

  }

  canBack++
  scroll(0, 0)
}

arrowBtn.addEventListener('click',  () => canBack > 1 ? window.history.back() : location.hash = '#')

en el curso de v8 y el navegador el Profe Diego nos dio una pista de como funcionaban el botón atrás de los navegadores, e hicimos un link list asi que meti cada Location.hash en el valor de cada link list donde el link list por defecto trae al home en el head y cada que el location.hash cambia le agrega un hijo , de este modo el hijo siempre volvera al padre.

class Node {
    constructor(value){
        this.value = value;
        this.prev = null;
        this.next = null;
    }
}
class MemoryBack  {
    constructor(value){
        this.head = {
            value: value,
            prev: null,
            next: null,
        }
        this.tail = this.head;
        this.length = 0;        
    }
    append(value) {
        const newNode = new Node(value);
        newNode.prev = this.tail;
        this.tail.next = newNode;
        this.tail = newNode;
        this.length++;
        return this;
    }
    prepend(value) {
        const newNode = new Node(value);
        newNode.next = this.head;
        this.head.prev = newNode;
        this.head = newNode;
        this.length++;
    }
}

const memoryBackBtn = new MemoryBack("#home");
console.log("initialbackbutton" , memoryBackBtn);
searchFormBtn.addEventListener('click', () => {
    location.hash = `#search=${searchFormInput.value}`;
});
trendingBtn.addEventListener('click', () => {
    location.hash = '#trends'
});
arrowBtn.addEventListener('click', () => {
    // history.back();
    if (memoryBackBtn.length === 1) {
        memoryBackBtn.head.next = null;
        memoryBackBtn.tail.value = memoryBackBtn.head
        memoryBackBtn.tail.next = null;
    }
    location.hash = memoryBackBtn.tail.prev.value;
    memoryBackBtn.tail= memoryBackBtn.tail.prev;
    memoryBackBtn.tail.prev.next = null;
    memoryBackBtn.length -= 1;
});


window.addEventListener('DOMContentLoaded', navigator, false);
window.addEventListener('hashchange', navigator, false);



function navigator() {
    console.log({ location })
    
if (location.hash.startsWith('#trends')){
    trendsPage();
    memoryBackBtn.append(location.hash); 
    console.log(memoryBackBtn);   
} else if (location.hash.startsWith('#search=')) {
    searchPage();
} else if (location.hash.startsWith('#movie=')) {
    movieDetailsPage();
    memoryBackBtn.append(location.hash); 
    console.log(memoryBackBtn);
} else if (location.hash.startsWith('#category=')) {
    categoriesPage();
    memoryBackBtn.append(location.hash); 
    console.log(memoryBackBtn);
} else {
    homePage();
}

bueno mi solución fue que primero cree un array vacío para ir almacenando mi query que lo usare mas adelante como argumento de una función igual a la función de búsquedas

const navigationHistory = [];

searchFormBtn.addEventListener('click', () => {
  location.hash = `#search=${searchFormInput.value}`;
  const [_, query] = location.hash.split('=');
  navigationHistory.push(query);
});

lo segundo que hice fue que cada ves que el botón arrow back lanza un evento pasa por la condición que cuando el array tiene mas de un elemento valla quitando elementos, dentro de la condición una función para que quite el ultimo elemento y también para que seleccione el ultimo elemento.
Luego ese ultimo elemento seleccionado se envía como argumento a la función backHistory que no es mas que una función similar a la de búsqueda.
Cuando el array queda con un solo elemento el próximo evento del botón será regresar al home

arrowBtn.addEventListener('click', () => {
  if(navigationHistory.length >= 2){
    function resolve () {
      navigationHistory.pop();
      //ultimo elemento del array
      const ultimateElement = navigationHistory[navigationHistory.length - 1];
      return ultimateElement;
    }
    backHistory(resolve())
  } else {
    location.hash = '#home';
  }
});

y esta es la funcion backHistory que recibe como argumento la query que fuimos almacenando en el array:

function backHistory(query) {
  console.log('back!!');
  console.log(query)
  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.add('inactive');
  searchForm.classList.remove('inactive');

  trendingPreviewSection.classList.add('inactive');
  categoriesPreviewSection.classList.add('inactive');
  genericSection.classList.remove('inactive');
  movieDetailSection.classList.add('inactive');

  getMoviesBySearch(query);
}

Quise colocarle un query-parameter a la seccion de tendencias en la pagina principal de que limite el numero de peliculas a mostrar, pero según revisé la documentación la API no posee ese tipo de query-parameter en el enpoint de trends, ya que lo hize con ?limit=5, pero no valio 😅

Para eliminar espacios en le input

Yo lo que hice fue crear una variable en el scope global del archivo navigation y le asigné el valor de 0.

cada vez que se llama a la función searchPage() dicho contador aumenta en 1.

Despues solo es poner un condicional en el evento de la flecha que pregunte si el contador es mayor a 1, si lo es envía a history.back(), de lo contrario envía a location.hash = ‘home’ .

arrowBtn.addEventListener('click', () => { if (count > 1) history.back(); else location.hash = 'home' })

Para cambiar el titulo cuando entramos a tendencia lo que hice fue ir a cambiar el valor en el index.html para que ese sea el nombre por defecto y que cambie solo cuando el cliente navegue por otra categoría.