No tienes acceso a esta clase

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

Convierte tus certificados en títulos universitarios en USA

Antes: $249

Currency
$209

Paga en 4 cuotas sin intereses

Paga en 4 cuotas sin intereses
Suscríbete

Termina en:

17 Días
0 Hrs
46 Min
55 Seg

Actualizando nuestro index.html para agregar la nueva funcionalidad de routing

12/13
Recursos

Aportes 38

Preguntas 8

Ordenar por:

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

Me gustaria que fuera mas practico, ir estructurando en orden el codigo y explicar que se hace en cada seccion.
Por ejemplo: con esta funcion guardamos el path de la url actual y en ese momento hacer una prueba imprimiendo la ruta por consola.

Tenía un problema, se me generaba el error “Uncaught TypeError: Cannot read property ‘template’ of undefined”. Esto se generaba porque se cargaba la ruta “localhost:8000/index.html”, la cual no estaba en nuestro archivo routes.js, entonces hay 2 maneras de solucionarlo, o agregas esa ruta a routes.js o simplemente borras el “index.html” de la url y tu página cargará sin problemas.

Realmente no me funcionó como el profe lo hizo. Aquí va mi solución, espero les sirva:




Me molesta como en las clases de programación empiezan a escribir código y hay que seguirlo, se saltan por completo la lógica. El método de Freddy con la tablet donde primero explica TOOOOOODOOOO lo que pasa en el programa y luego empieza a codear es perfecto, no se porque no se lo exigen a todos los profesores, sobre todos los de js…que insisto…empiezan a agregar código y por alguna razón piensan que los que estamos aprendiendo les podemos seguir el ritmo.

La solución creo que esta un poco rebuscada, les comparto mi solución

Path.js

const PATHS = {
    home: {
        path: "/",
        template: "<h1>Home 🏠</h1>",
    },
    about: {
        path: "/about",
        template: "<h1>Sobre mi 👨🏻‍💻</h1>",
    },
    contact: {
        path: "/contact",
        template: "<h1>Contacto 📲</h1>",
    },
    error: {
        path: "/",
        template: "<h1>Error ⛔️</h1>",
    },
}

Router.js

class Router {
    /**
     * Metodo inicial.
     *
     * @return {void}.
     */
    constructor(paths) {
        this.paths = paths;
        this.initRouter();
    }

    /**
     * Permite inicializar el router
     *
     * @return {void}.
     */
    initRouter() {
        const { location: { pathname = "/" } } = window;
        const URI = pathname === "/" ? "home" : pathname.replace("/", "");
        this.load(URI);
    }

    /**
     * Permite iniciar la carga de paginas.
     *
     * @return {void}.
     */
    load(page = "home") {
        const { paths } = this;
        const { path, template } = paths[page] || paths.error;
        const $CONTAINER = document.querySelector("#content");
        $CONTAINER.innerHTML = template;
        window.history.pushState({ }, "Genial", path);
    }

}

const ROUTER = new Router(PATHS);

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Manejo de Routers</title>
 </head>
<body>
    <header>
        <nav>
            <ul>
                <li>
                    <button id="Home" onclick="ROUTER.load('home')">Home</button>
                </li>
                <li>
                    <button id="About" onclick="ROUTER.load('about')">About</button>
                </li>
                <li>
                    <button id="Contact" onclick="ROUTER.load('contact')">Contact</button>
                </li>
            </ul>
        </nav>
    </header>
    <section>
        <div id="content">
        </div>
    </section>
    <footer></footer>
    <script src="./Paths.js"></script>
    <script src="./Router.js"></script>
</body>
</html>

Con esa explicación del final me quedó más claro lo que estábamos haciendo! 😄

mi ejemplo de lo aprendido en este curso yo agregue botones con class de **bootstrap **

Yepaaaaa!!! al fin se probara el código, vaya mas mierda de profe

Hola compañeros, me pasó que si escribo una ruta que no existe, el programa se rompe, para resolver el error, agregué en la función _matchUrlToRoute una condición antes del return que devuelve un objeto con solo la propiedad template

if (matchedRoute === undefined) {
	return {
		template: '<h1>Not found</h1>'
	};
}

return matchedRoute;

Me ha gustado mucho el curso y creo que es bastante útil: Felicito al profesor por su entusiasmo y la materia aportada pero creo que debería haberlo preparado mejor. Por ejemplo, ir probando resulatdos parciales y no esperar hasta el final para que todo funcione con el último return. Algunas explicaciones también dejan algo que desear. Espero que se tome mi comentario como una critica constructiva alejada por supuesto de la intencionalidad de comunuicar una verdad absoluta y de nuevo le doy las gracias al profesor por haberme ayudaddo a aprender. Pero Platzi no es cualquier academia sino la puerta abierta del conocimiento digital a muchísima gente. Si entre todos conseguimos que sea aún mejor de lo que es, nos beneficiaremnos por partida boble o tal vez triple.

Saludos
Vicent

Un gran curso la verdad, me gusta la lógica con la que el profesor trabaja y aprendí nuevos conceptos de JS. Me funcionó todo perfecto, acá les dejo mi código.
index.html

routes.js

router.js

index.js

He creado mi propia solucion porque no me iba el evento onclick

  <body>
    <header>
      <ul>
        <li>
          <button data-router="">Home</button>
        </li>
        <li>
          <button data-router="portfolio">PorFolio</button>
        </li>
        <li>
          <button data-router="aboutme">About Me</button>
        </li>
        <li>
          <button data-router="contact">Contact</button>
        </li>
      </ul>
    </header>
    <div id="root"></div>
    <script src="./index.js" type="module"></script>
  </body>
const routerOutElm = document.querySelector("#root");
import Router from "./router.js";
import { routes } from "./routes.js";

/* Seleccionamos los botones */
const btnListRoute = [...document.querySelectorAll("[data-router]")];

/* Genero eventos Cliks del menu de navegación */
btnListRoute.forEach((btn) => {
  btn.addEventListener("click", () => {
    router.loadRoute(btn.dataset.router);
  });
});

/* Declaro la instancia de Router */
const router = new Router(routes);```


Resultado de la ventana Ayuda del curso.

Si les sirve. Me tope con el error “router is not defined”, y me encontré con que el error o mi error se estaba en el onclick, que utilizábamos en html.

En lugar de eso lo hice de esta forma.

se olvido de dejar el codigo para poder amalizarlo mejor

Tengo aun este error, ya trate de debuggear pero no encontre como solucionarlo, compañeros en esta clase llegaron a tener el mismo problema, uso VS con Live Server

router.js:14 Uncaught TypeError: Cannot read property 'template' of undefined
    at Route.loadRoute (router.js:14)
    at Route._loadInitialRoute (router.js:36)
    at new Route (router.js:4)
    at index.js:1
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Curso/Taller SPA</title>
</head>

<body>
    <header>
        <ul>
            <li><Button onclick="router.loadRoute('')">Home</Button></li>
            <li><Button onclick="router.loadRoute('contact')">Contacto</Button></li>
            <li><Button onclick="router.loadRoute('about')">Acerca de mi</Button></li>
        </ul>
    </header>
    <div data-router>
        <!-- Builder -->
    </div>
    <script src="router.js"></script>
    <script src="routes.js"></script>
    <script src="index.js"></script>
</body>

</html>
const routes = [
    {
        path: '/',
        template: '<h1>Hola</h1>'
    },
    {
        path: '/contact',
        template: '<h1>Contacto</h1>'
    },
    {
        path: '/about',
        template: '<h1>Acerca de mi</h1>'
    },
    {
        path: '/index.html',
        template: '<h1>Home</h1>'
    }
];
class Route {
    constructor(routes) {
        this.routes = routes;
        this._loadInitialRoute();
    }

    loadRoute(...urlSegs) {
        const matchedRoute = this._matchUrlToRoute(urlSegs);
        // debugger
        const url = `/${urlSegs.join('/')}`;
        history.pushState({}, 'This works', url);
        // debugger
        const routerOutElm = document.querySelectorAll('[data-router]')[0];
        routerOutElm.innerHTML = matchedRoute.template;
    }

    _matchUrlToRoute(urlSegs) {
        const matchedRoute = this.routes.find(route => {
            const routePathSegs = route.path.split('/').slice(0);
            // debugger
            if (routePathSegs.length !== urlSegs.length) {
                // debugger
                return false;
            }
            // debugger
            return routePathSegs
                .every((routePathSeg, i) => routePathSeg === urlSegs[i])
        });

        if (matchedRoute === undefined) {
            return {
                template: '<h1>Not found</h1>'
            };
        }

        return matchedRoute;
    }

    _loadInitialRoute() {
        const pathNameSplit = window.location.pathname.split('/');
        const pathSegs = pathNameSplit.length > 1 ? pathNameSplit.slice(1) : '';

        this.loadRoute(...pathSegs)
    }
}
const router = new Route(routes);

Trate de arreglarlo con una validacion sugerida, sin embargo NO funciona

Una pequeña acotación para MEJORAR el rendimiento en su código. En el condicional donde se comparan los arrays, hay un pequeño error:

const matchedRoute = this.routes.find( (route) => {
            const  routePathSegs = route.path.split("/").slice(1)

	    // ESTE
            if(routePathSegs.length !== urlSegs.length){
                return false
            } 

            return routePathSegs
                .every((routePathSeg, i) => routePathSeg === urlSegs[i])
        })

Acá lo que se explicó es que se querian comparar los strings de ambos arrays, tanto de routePathSegs
como urlSegs, pero si debuggean su código y ven lo que hace paso a paso, se darán cuenta que nunca entra al condicional porque así como estaroutePathSegs.length !== urlSegs.length Lo que hace es comparar el tamaño del array en sí y por como han sido trabajados con los métodos slice() y split() siempre tendran un length de 1, así que esa comparación no funciona.

Entonces, porque si funciona el código en general? por el metodo every(), donde se comparan que si sean iguales.
.

Optimización

Para optimizar el código y entre al if cuando sean de tamaños distintos solo hace falta agregar:

 if(routePathSegs[0].length !== urlSegs[0].length){
                return false
            }

Como les dije, siempre es un array de un elemento así que su índice siempre será 0. Con este cambio los valores diferentes entraran al condicional, retornaran false y permitirán la siguiente iteración, sin necesidad de pasar por el every()

Hola todos, espero estén bien, yo al momento de ejecutar el código tengo este error, alguien que me de una mano, se los agradecería mucho.

Para sacarle provecho a este codigo habira que crear templates en archivos externos y pasarlos en vez de escribir el template directamente en el archivo routes.js

Despues de seguir todo el curso, no me funciona. He repasado el codigo de los archivos y en consola tengo este error:

router.js:13 Uncaught TypeError: Cannot read property 'template' of undefined at Router.loadRoute (router.js:13) at Router._loadInitialRoute (router.js:36) at new Router (router.js:4) at index.js:1

Lo modifique para que tenga un template de error404 si no exite la pagina dentro de los array de routes. aqui

Este es mi aporte, corrige lo que no funcionaba y le agregue not found en caso de que la ruta no este disponible.

class Router {

    constructor (routes) {
        this.routes = routes;
        //Para cargar ruta inicial del proyecto
        this._loadInitialRoutes();
    }
    
    loadRoutes(...urlSegs){
        const matchedRoute = this._matchUrlToRoute(urlSegs);
        const url = `/${urlSegs.join('/')}`;
        window.history.pushState({},'this word',url);
        const routerOutElem = document.querySelectorAll(['#data-router'])[0];
        routerOutElem.innerHTML = matchedRoute.template;
    }

    _matchUrlToRoute(urlSegs){
        const notFound = this.urlNotFound();
        const matchedRoute = this.routes.find ( route => {
        const routePathSeges = route.path.split('/').slice(1);
            if (routePathSeges === ''){
                return '/'
            }else if (routePathSeges[0] === urlSegs[0] ){
                return route;
            }
        })
        // En caso de no encontrar la ruta retorna 404
        const urlMatch = matchedRoute !== undefined ? matchedRoute : notFound
        return urlMatch;
    }

    // Busco el path 404 
    urlNotFound() {
        const notFound = this.routes.find(route => {
            return route.path ==='/404';
        })

        return notFound;
    }


    _loadInitialRoutes(){
        const pathNameSplit = window.location.pathname.split('/');
        const pathSegs = pathNameSplit.length > 1 ? pathNameSplit.slice(1) : '';
        this.loadRoutes(...pathSegs);
    }
}

Es mejor modularizar los scripts, así sólo llamas uno.

KeMonito!

Si tienen una ruta como /user/andrea/picture2 tienen que pasarle un array a router.loadRoute(), en este ejemplo sería router.loadRoute([‘user’, ‘andrea’, ‘picture2’])

tengo el siguiente error:
Uncaught ReferenceError: routes is not defined
at index.js:1
revise el código pero no encuentro lo malo

index

const router =  new Router(routes);

routes

const route = [
    {
        path: '/',
        template: '<h1>Hola</h1>'
    },
    {
        path: '/contacto',
        template: '<h1>contacto</h1>'
    },
    {
        path: '/aboutme',
        template: '<h1>About me</h1>'
    }
];


router

class Router{

    constructor(routes) {
        this.routes= routes;
        this._loadInitialRoute();
    }

    loadRoute(...urlSegs){
        const matchedRoute = this._matchUrlToRoute(urlSegs);

        const url = `/${urlSegs.join('/')}`;
        history.pushState({},'this works', url);

        const routerOutElm = document.querySelectorAll('[data-router]')[0];
        routerOutElm.innerHTML = matchedRoute.template;
    }

    _matchUrlToRoute(urlSegs) {
        const matchedRoute = this.routes.find(route =>{
            const routePathSegs = route.path.split('/').slice(1)

            if (routePathSegs.lenght !== urlSegs.leng){
                return false;
            }

            return routePathSegs
            .every((routePathSeg, i) => routePathSeg === urlSegs[i]);
            
        });

return matchedRoute;

    }

    _loadInitialRoute() {

        const pathNameSplit =window.location.pathname.split('/');
        const pathSegs = pathNameSplit.length > 1 ? pathNameSplit.slice(1): '';
        
        this.loadRoute(...pathSegs);
    }
}

su ayuda 😒

No funca 😌

Hola, me sale el error Uncaught TypeError: matchedRoute is undefined. Ya estoy cansado de leer el código. alguien tuvo este problema?

alguien me puede explicar esta línea ?
no entiendo porque el objeto vacío y el mensaje

history.pushState({}, 'this works', url)

Hola!

  • Primero si tuvieron errores a la hora de cargar rutas específicas, puede ser porque están usando Live-server, en es caso deben de usar el servidor propuesto por el Ricardo! 😎

  • Segundo yo realicé una implementación simplificando un poco más todo, los invito a que la miren en el Repositorio

Y les comparto el código del Router

y el Index

Así quedó

¿al colocar en los scripts src=’…/’ no saldría del entorno de desarrollo donde se encuentra trabajando?, si no me equivoco hay un error allí.

Demasiados errores en el código, deberían de pasar un filtro mínimo antes de poder subir el curso. Aquí el código que me funciono usando Live Server

index.html

<!DOCTYPE html>
<html lang="es">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Cliente de nuestro SPA Router</title>
</head>

<body>
    <header>
        <ul>
            <li><button onclick="router._loadRoute('index.html')">Home</button></li>
            <li><button onclick="router._loadRoute('contacto')">Contacto</button></li>
            <li><button onclick="router._loadRoute('aboutme')">About me</button></li>
        </ul>
    </header>
    <div data-router>
    </div>
    <script src="/router.js"></script>
    <script src="/routes.js"></script>
    <script src="/index.js"></script>
</body>

</html>

routes.js

const routes = [{
        path: '/index.html',
        template: '<h1> Hola </h1>'
    },
    {
        path: '/contacto',
        template: '<h1> Contacto </h1>'
    },
    {
        path: '/aboutme',
        template: '<h1> About Me </h1>'
    },
];

router.js

class Router {
    constructor(routes) {
        this.routes = routes;
        this._loadInitialRoute();
    }

    _loadRoute(...urlSegs) {
        const matchedRoute = this._matchUrlToRoute(urlSegs);
        const url = `/${urlSegs.join('/')}`;
        history.pushState({}, 'this works', url);
        const routerOutElm = document.querySelectorAll('[data-router]')[0];
        routerOutElm.innerHTML = matchedRoute.template;
    }

    _matchUrlToRoute(urlSegs) {
        const matchedRoute = this.routes.find(route => {
            const routePathSegs = route.path.split('/').slice(1);
            if (routePathSegs.length !== urlSegs.length) {
                return false;
            }
            return routePathSegs.every((routePathSegs, i) => routePathSegs === urlSegs[i])
        });
        return matchedRoute;
    }

    _loadInitialRoute() {
        const pathNameSplit = window.location.pathname.split('/');
        const pathSegs = pathNameSplit.length > 1 ? pathNameSplit.slice(1) : '';
        this._loadRoute(...pathSegs);
    }
}

index.js

const router = new Router(routes);

Con el error, que soluciono Ricador en el minuto 3:20, me ha funcionado. aquí mi implementación.

Index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Router</title>
    <link rel="preconnect" href="https://fonts.gstatic.com">
    <link href="https://fonts.googleapis.com/css2?family=Montserrat:wght@100;300;600&display=swap" rel="stylesheet">
    <style>
        body, * {
            margin:0px;
            padding: 0px;
        }

        body{
            background: rgb(254,254,254);
            background: radial-gradient(circle, rgba(254,254,254,1) 0%, rgba(227,225,225,1) 35%, rgba(228,228,228,1) 100%);
            font-family: 'Montserrat', sans-serif;
            position: relative;
        }

        header{
            width: 100vw;
            height: 80px;
            background-color: #fed049;
        }

        header ul {
            display: flex;
            flex-wrap: nowrap;
            justify-content: space-evenly;
            list-style: none;
            height: 100%;
            align-items: center;
        }

        header ul li span{
            font-size: 24px;
            cursor: pointer;
        }

        section{
            width: 100%;
            position: relative;
        }

        section .wrapper{
            width: 80%;
            margin: 0 auto;
            text-align: center;
            position: relative;
            padding: 5% 10%;
        }

        section .wrapper h1{
            font-size: 40px;
        }

        section .wrapper p{
            margin: 35px 10px 15px;
            padding: 0px 15px;
        }
    </style>
</head>
<body>
    <header>
        <ul>
            <li class="home"><span>Home</span></li>
            <li class="aboutus"><span>About Us</span></li>
            <li class="contactus"><span>Contact Us</span></li>
        </ul>
    </header>

    <section>
        <div class="wrapper">
            <h1> Welcome goide :) </h1>
            <h2> Make a Router with JavaScript Vanilla.</h2>
            <p>
                Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec sed justo in metus imperdiet interdum. Aliquam vestibulum in est vitae semper. In ornare rhoncus mi, a malesuada enim eleifend ac. Duis non elit eros. Maecenas fringilla semper lorem, et interdum nibh blandit sit amet. Ut quam nisi, elementum eget maximus a, pretium hendrerit quam. Integer congue congue turpis eget suscipit. Sed a sollicitudin est, malesuada varius erat. Aliquam tincidunt nisl id nibh placerat, auctor auctor odio tincidunt. Proin commodo aliquam libero mollis lacinia.
            </p>
        </div>
    </section>

    <script src="/src/router.js"></script>
    <script src="/src/routes.js"></script>
    <script src="/src/index.js"></script>

</body>
</html>

Routes.js

const routes = [
    {
        path: '/',
        template: `Welcome goide :)`
    },
    {
        path: '/about-us',
        template: `About Us`
    },
    {
        path: '/contact-us',
        template: `Contact Us`
    }
];

Router.js

class Router{
    constructor(routes){
        this.routes = routes;
        this._loadInitialRoutes(); 
    }

    loadRoute(...urlSegs){
        const matchedRoute = this._matchUrlToRoute(urlSegs);

        const url = `/${urlSegs.join('/')}`;
        window.history.pushState({}, 'this works', url);

        const routerOutElm = document.querySelector('h1');
        routerOutElm.innerHTML = matchedRoute.template;
    }

    _matchUrlToRoute(urlSegs){
        const matchedRoute = this.routes.find( route => {
            const routePathSegs = route.path.split('/').slice(1);

            if(routePathSegs.length !== urlSegs.length){
                return false;
            }

            // El emtodo every nos permite, Determina si todos los elementos en el array satisfacen una condición.
            // o sea verifica cada elemento del array que todos sean true, en este caso es una letra, las verifica letra por letra
            return routePathSegs.every((routePathSeg, i) => routePathSeg === urlSegs[i]);
        });

        return matchedRoute;
    }

    _loadInitialRoutes(){
        // vamos a usar el metodo split, El método split() divide un objeto de tipo String en un array (vector) de cadenas mediante la separación de la cadena en subcadenas.
        // en este caso: split('/') -> nos separa todo lo de la parte derecha luego del slash de la url
        const pathNameSplit = window.location.pathname.split('/');
        // Segmentar nuestro path
        // el metdo slice, devuelve una copia de una parte del array dentro de un nuevo array empezando por inicio hasta fin (fin no incluido).
        const pathSegs = (pathNameSplit.length > 1) ? pathNameSplit.slice(1) : '';

        this.loadRoute(...pathSegs);
    }

}

Index.js

const router = new Router(routes);

const pathHome = () => {
    console.log('Home')
    router.loadRoute('');
}

const pathAbout = () => {
    console.log('About - Us ')
    router.loadRoute('about-us');
}

const pathContact = () => {
    console.log('Contact - Us ')
    router.loadRoute('contact-us');
}

const home = document.querySelector('.home');
home.addEventListener('click', pathHome);

const about = document.querySelector('.aboutus');
about.addEventListener('click', pathAbout);

const contact = document.querySelector('.contactus');
contact.addEventListener('click', pathContact)

Podemos agregar una pagina 404 si en el return de _matchUrlToRoute agregamos esto

    return matchedRoute ? matchedRoute : this.routes[this.routes.length - 1]

y en la parte de routes agregamos al final un template de 404

Buenas tardes chicos , implemente la solución de colocar en la ruta index.html, y me carga perfectamente juntamente con los templates de contacto y about... pero cuando me coloco en una de estas dos últimas me aparece el error cannot GET contacto/ y también en cannot GET /about... el codigo está igual al del profesor a excepción de ms modificación que describí al principio alguno pudo solucionar??? necesito ayuda 😟😟😟😟😟😟

platzi terminaran siendo un libro digital, te dan toda la info, pero nuevamente vuelves tu a tener que estudiar todo hasta que lo entiendas, por lo menos los creadores de contenido de youtube, se toman hasta 2 -3 horas explicando las funcionalidades de las cosas, aca nuevamente graban lo que leen de otra pantalla y listo, curso terminado, estudien ahora si.

f

Les comparto mis apuntes de todo el curso por si se pierden en algún momento: https://app.gitbook.com/@afgallegoz/s/creacion-de-router-spa/