This graph shows how many times the word ______ has been mentioned throughout the history of the program.
Hoy vamos a hacer una prueba técnica, una prueba técnica que además es bastante top.
Es una prueba técnica real para una empresa muy top y la he sacado de este artículo.
Este artículo, este blog, es de Surma.
Surma, no sé si sabéis quién es, Das Surma, es un chico que trabajaba en Google, ¿vale?
Trabajaba en Google y ahora trabaja en Shopify.
Es un verdadero crack muy, muy bueno sobre el mundo de la programación y el desarrollo.
Y la verdad es que en este artículo explicaba una prueba técnica que le habían puesto para entrar en Shopify.
Donde además tenía como menos de dos horas para hacerlo.
Es tremendo, ¿eh? Me encanta. Menos de dos horas para hacerlo.
Lo más interesante de esto es que este artículo lo recomiendo mucho porque en este artículo además os explica cómo él se acercó al problema.
Cómo dijo, oye, ¿cuál es el problema que hay que hacer?
Más o menos que tenía una hora y cómo él lo intentó resolver paso a paso.
Lo cual está súper bien porque fijaos, incluso con código, cómo lo fue pensando y tal.
¿Y cuál es el problema que le pidieron que tenía que hacer?
El problema que tenía que resolver era crear un Excel.
Amigos y amigas, un Excel.
O sea, el Excel de toda la vida de Office.
Pues eso. Y se lo pidieron hacer con React. Eso sí.
O sea, ellos se lo pidieron hacer con React.
No es que le pidieron terminar el Excel entero.
Porque ya muchas veces la gente me dice, ¿cómo vas a hacer un Excel en dos horas?
Obviamente no.
Pero es intentar crear algo que te recuerde a que es un Excel.
Y esto es una cosa muy típica de pruebas técnicas.
Y aquí podéis ver cómo poco a poco fue intentando resolverlo.
Cómo lo iba iterando.
Cómo iba pensando.
Porque esto muchas veces es lo que quieren.
Ver cómo vas pensando las cosas que hacen, ¿no?
Entonces, está muy interesante.
Pero os digo que esto lo estaba haciendo con React.
Tiene algunas cosas que, bueno, aquí el cambiar los valores y tal.
Está muy bien.
Pero he pensado, esto está genial, pero no lo vamos a hacer con React.
¿Qué tal si hacemos esta prueba técnica y la hacemos directamente con JavaScript?
Porque como tenemos esto de JavaScript 100.dev,
que estamos trabajando en hacer 100 proyectos prácticos de JavaScript con su código,
con el vídeo, que las hagamos aquí en vivo y en directo,
que ya llevamos 7 y que estamos haciendo cosas muy chulas,
pues qué tal si hacemos un octavo, que sea una prueba técnica,
donde vamos a hacer un pequeño Excel.
Y creo que podemos hacerlo.
Creo que podemos hacer este Excel, pero un poquito más bonito, ¿vale?
Para añadirlo.
Y me parece un proyectazo porque además luego al final os voy a mandar ejercicios
para que vosotros también podáis llevar, pues, este desarrollo hasta donde queráis.
Podéis hacer un Excel.
Hoy vamos a empezar a hacer muchas cosas,
pero este Excel lo podéis empezar a iterar
y realmente intentar hacer alguna cosa hasta el final, ¿no?
Midu, vos con tus ocurrencias me estás haciendo prender la máquina para programar.
Hombre, claro, ¿cómo tiene que hacer?
¿Cómo tiene que ser?
Hombre, hay que mover las manitas.
Hay que hacer la manita, ¿eh?
Entonces, ¿qué vamos a hacer?
Vámonos por aquí.
Mira, ya tengo JavaScript 100 proyectos
y vamos a crear un nuevo proyecto por aquí.
Fijaos qué bonito está quedando este...
No sé, no sé vosotros, pero yo creo que es un repositorio muy bonito.
Que sea en español, que sean todos los proyectos.
Harán los 100 proyectos en directo.
Hay alguno que no lo hemos hecho en directo porque está en vídeo.
En vídeo como mínimo habrá, eso sí, ¿eh?
Vamos a añadir aquí el index.html y venga, vamos a hacer ya nuestro querido Excel.js
y la vamos a ir haciendo paso a paso, ¿vale?
Poco a poco.
Así que, lo primero, un HTML básico.
Yo utilizo este shortcut que si pones la exclamación y le das al Enter, ya te aparece todo esto.
Vamos a llamarle Excel.js por ponerle un nombre a esto.
Y lo que vamos a necesitar, primero, un estilo muy sencillo.
Voy a iniciar el servidor.
Voy a entrar aquí, Excel.js.
Ahora le damos un poquito de estilos.
A ver, podríamos ponerle modo oscuro, pero la verdad es que el Excel es muy blanco.
Entonces, vamos a hacerlo así, ¿vale?
Y voy, lo que sí que voy a hacer, para que se note que es un Excel,
porque si no la gente va a estar diciendo,
¡Ay, pero esto qué es!
Mira, Excel.js también.
No, Excel.js no, vamos a poner Excel logo.
Voy a cargar este logo, este mismo, el de la Wikipedia.
Lo vamos a poner por aquí, vamos a poner esto por acá, vamos a poner source, ¿vale?
Ahora arreglamos estos estilitos un poco, max width, vamos a ponerlo más pequeñito, auto, ¿vale?
Y ahora haremos aquí.
Una cosa muy interesante del Excel, realmente hay un elemento HTML que la gente odia y no debería.
Hay un elemento HTML que la gente le tiene pavor y con razón, que es el hecho del table.
El table, ¿no? Table.
Pero, ¿sabéis una cosa? Que en el Excel, la verdad es que tiene sentido...
Se podría hacer con un grid, también os digo, ¿eh?
Podríais utilizar div, utilizar un grid y tal.
Pero creo que semánticamente, y como lo vamos a hacer, tiene todo el sentido del mundo que sea una tabla.
Porque literalmente el Excel son tablas.
Literalmente son tablas.
Así que vamos a utilizar el table, que tiene todo el sentido del mundo, utilizar el table.
Y así, pues mira, también lo refrescamos.
¿Cuántos años hará que no utilicéis el table?
Seguro que 10.000 millones de años.
Pues vamos a tener aquí el table, donde dentro vamos a tener como la cabecera y vamos a tener luego el cuerpo, ¿vale?
Por ahora, ahora mismo no sale absolutamente nada.
Lo primero que vamos a tener que hacer es dibujar las tablas.
Vamos a dibujar aquí las tablas.
Va a ser nuestro primer objetivo dibujar tablas, para que esto tenga algún sentido.
Vamos a poner que el script sea del tipo módulo.
Que esto es lo que nos permitiría es utilizar import y export.
Y además, va a hacer que este JavaScript se evalúe después de renderizar el HTML.
Y así lo podemos dejar en el head.
Y no hacemos el típico, la cosa esta típica que hace la gente de poner el script ahí abajo.
Que no tiene mucho sentido a día de hoy, ¿vale?
Voy a crear dos, muy bien, dos utilidades.
Ya se está sabiendo.
La inteligencia artificial ya sabe cómo trabajo.
Vale, estas son dos utilidades que utilizamos el otro día también.
Para simplificar la forma que recuperamos los elementos del DOM.
En lugar de repetir document.querySelector, pues utilizamos un dólar para recuperar un elemento,
dos dólares para recuperar una lista de elementos.
No sé si necesitamos el de dos dólares, pero igualmente así lo tengo de la mano.
Voy a definir aquí unas constantes.
Voy a poner que vamos a tener diez filas y vamos a poner que tenemos tres columnas.
Esto ahora mismo no es importante.
Lo que es importante es que realmente luego podamos cambiar esto para definir y cambiar
pues cómo son las tablas de Excel que vamos a crear, ¿vale?
Y aquí vamos a crear una utilidad que le voy a llamar range.
Porque por desgracia en JavaScript no existe una forma declarativa de hacer algo X veces, ¿vale?
O sea, podemos hacer, por ejemplo, si nos vamos al rangees y os lo enseño en un momento.
Podríamos hacer, claro, de forma declarativa, ¿eh?
Que esto mucha gente al final se...
Claro, podríamos hacer let cero while i...
Perdón.
Let i igual a cero.
Mientras la i sea menor a cinco, ¿vale?
Pues i más, más.
Y esto pues vas a hacer aquí ¿cuántas veces?
Pues las veces que diga.
Vale, pues cinco veces hemos hecho esto.
Claro, esto no es declarativo.
Lo que me refiero es hacer algo así como haz...
Lo más cercano es esto, que le podemos decir.
Crea un array de longitud cinco y aquí le podemos crear esto y entonces mapear.
Hola, Miru.
Hace algunos días te dije que tenía una startup que me generaba aproximadamente un salario en mi trabajo de tiempo completo.
Y me dijiste que aprovechara la oportunidad.
Dejé mi trabajo hoy para jugármela completamente por mi startup.
Quería compartirte mi felicidad.
Qué grande, ¿no, amigo?
Qué grande, joder.
Oye, pues felicidades.
Me alegro un montón, ¿eh?
Muy, muy, muy bien, ¿eh?
Muy bien, muy bien.
¡Buah!
Mucho ánimo, mucha suerte a por todas y...
Bueno, la gente haciéndote F.
Yo no creo que sea una F, ¿eh?
Yo no creo que sea una F.
Yo creo que es tu momento y que si te estás sacando un salario, imagínate,
si le dedicas más tiempo, pues yo creo que te puede ir mejor.
Así que mucha suerte, éxito y la vida es para los valientes, ¿sabes?
O sea, ¿sabes lo que pasa?
Que la gente cuando...
Y que estoy seguro que encontrarías trabajo.
O sea, estoy seguro y estoy convencido de ello que encontrarías trabajo en el caso que lo necesitases.
Pero el tema es que hay veces en la vida que hay que jugársela.
Hay que jugársela.
Así que si sale mal, culpamos a Miru.
Bueno, también es verdad.
Pero aunque te salga mal, algo habrás aprendido.
De eso estoy bastante seguro.
Bueno, pues esto sería una forma como más declarativa.
Hay otras, porque también podéis hacer aquí, le podéis pasar, podéis sacar las keys de esto.
Y una vez que tenéis las keys, pues ya podéis hacer el forEach, ¿no?
También esto, console.log.
Hola, si no me equivoco, pues no.
El keys no funciona.
¿Cómo era el otro?
El otro es el array from.
Array from.
Bueno, no me acuerdo.
Da igual, ¿qué más da?
O sea, podéis sacar array.keys.
¿No es así?
No.
Bueno, no me acuerdo.
O si no, así, así seguro que sí.
Así, así seguro que sí.
Así seguro que sí.
¿Veis?
Ya lo podéis hacer.
Esta sería otra.
Es que hay un montón de formas de hacerlo.
¿Veis?
Hay un montón de formas de hacerlo, pero no hay una forma nativa, sino que hay que empezar
a crearlo.
Un forOff no tiene sentido, porque estamos diciendo como de hacerlo de forma declarativa.
Que no pasa nada.
No es que sea malo ni nada.
Pero bueno, totalmente.
El tema que vamos a poner aquí, vamos a crear una que sea length.
Length, y le vamos a pasar el length.
Este ya va bien.
No pasa nada.
Podemos pasarle este, o utilizar el de keys, el que sea.
Pero vamos a tener un método para que nos cree un rango que sea fácilmente iterable.
¿Vale?
Y ya vamos a tener aquí un render spreadsheet o sheets.
Spread sheet.
Venga, spreadsheet.
¿Vale?
Y aquí vamos a traernos la tabla que ya hemos dibujado.
¿Vale?
Tenemos el table.
Vamos a traernos también el tbody.
O vamos a llamarle body directamente, porque total.
Aquí podríamos ir directamente...
Obviamente, esto lo hacemos porque no tenemos más cosas en HTML y así es sencillo.
Pero lo ideal, a lo mejor, sería que esto estuviese mejor separado con otros nombres y tal.
Y aquí esto fuesen clases.
Pero bueno, quiero enfocarme en lo que vamos a hacer.
No en que empecemos a poner un montón de class names y todo esto.
Vamos a dibujar primero el header.
¿Vale?
De nuevo, esto lo podemos hacer de diferentes formas.
Pero yo creo que tampoco amerita que empecemos a crear los elementos a mano y todo esto.
Así que lo que voy a hacer es escribir aquí como una fila y luego tendríamos aquí también...
Venga, voy a poner aquí otra fila.
Y aquí ya podríamos decirle que el head va a tener en el innerHTML...
Vamos a introducir este HTML que hemos creado aquí.
¿Vale?
Este que tenemos aquí.
Y en el body, pues lo mismo.
Y ahora lo llenamos en condiciones.
InnerHTML...
Se puede hacer con innerHTML, insert o appendChile, insertHTML...
En este caso, como total está vacío, no hay absolutamente nada.
Tampoco vale la pena que estemos hablando de un append y tal.
Eso normalmente se hace cuando no quieres machacar el contenido HTML que hay dentro.
¿Vale?
Entonces, en este caso vamos a utilizar innerHTML, que además suele ser bastante rápido cuando está vacío el elemento del DOM.
Y ya está.
Y lo que haremos ahora, ahora sí, aquí en el headerHTML, vamos a dibujar el correcto...
La parte de arriba de Excel.
Si miramos Excel, fijaos cómo es aquí arriba.
Es verdad que aquí empieza por la G, H, I, J...
Debería empezar por la A.
Y fijaos que el primero, que es este, está vacío.
O sea, que tenemos que dejar aquí un elemento TH vacío.
Si te estás preguntando qué es esto de TH, el TR, digamos que es la fila entera.
Y el TH sería un elemento especial que se está utilizando dentro del T-Head para indicar la celda que tendríamos dentro de la cabecera.
La primera la dejamos vacía y las demás vamos a utilizar aquí nuestro...
Bueno, qué maravilla de autocomplete.
Vale, vamos a hacer un rango con las columnas.
Y vamos a mapear cada columna de forma que cada...
Vamos a ponerle el ahí.
Cada columna vamos a renderizar un TH donde dentro tenga el índice.
Cerramos el TH, vale, TH y hacemos un join de todo esto.
Y con esto, sí, a ver, y con esto que veo que todavía no me funciona, ¿por qué no me funciona esto?
Puede ser que sea porque no...
A ver, a ver, a ver, a ver esto, a ver si hay algún error por aquí.
No hay ningún error.
Y en los elementos, vamos a ver la tabla, vale, el T-Head, me la he liado en alguna cosa.
O por qué no me está renderizando, a ver si lo veis vosotros.
A ver, esto es por culpa de utilizar tablas.
El T-Head, esto está bien.
Ah, que no estoy ejecutando, no estoy ejecutando esto.
Claro, no estoy ejecutando la función.
Hay que ver, hay que ver, empezamos bien, empezamos bien.
Vale, vale, es porque pensaba que la había puesto fuera de una función, vale, vale.
Pensaba que estaba en el cuerpo y digo, ¿por qué no me funciona?
Y es porque no estaba utilizando la función.
Ahora sí, ahora sí.
Vale, ya tengo 0, 1, obviamente ahora se ve un poco regular,
pero lo importante es que si yo le digo ahora que quiero 10 columnas,
ya me está empezando a poner esto.
Vale, hasta aquí más o menos bien.
Luego veremos por qué esta no va a ser las columnas correctas que nosotros queremos.
Pero vamos a dibujar el body para darle un poquito más de, una cosa interesante esto.
Aquí lo que vamos a tener que hacer es utilizar el TD.
De nuevo, aquí a la izquierda del todo, si nos fijamos en Excel,
aquí están los números, 1, 2, 3.
Esta primera columna que tenemos aquí, que tenemos los números,
es la que vamos a dibujar ahora.
O sea, que esto sería el row más 1, porque empieza en 1, no empieza en 0.
Vale, entonces la columna, la primera, siempre va a tener el número.
Y luego después, lo que deberíamos tener serían todas las celdas vacías.
Todas las celdas vacías.
Así que vamos a poner aquí otro TD.
Y dentro de cada, bueno, dentro de cada TD no,
utilizamos el rango, ¿vale?
Y dentro es que vamos a crear todas las columnas vacías.
Entonces lo mismo, hacemos el map, ¿vale?
Para cada uno de estos, vamos a tener aquí la columna.
Y aquí que devuelva un string vacío, ¿vale?
Bueno, por ahora es un string, pero ahora lo vamos a poner lo interesante.
¿Vale? TD, TD.
Vale, en esta celda vamos a poner la información, por ejemplo, de su posición.
Esto, por si, no sé si lo necesitaremos, pero puede ser interesante.
El tener un data ahí que nos diga la posición X y la posición Y.
Así que vamos a poner tanto la columna como la fila.
Y dentro vamos a poner dos cosas.
Uno, un span vacío.
Luego ya verás para qué.
Y luego un input, ¿vale?
Vamos a poner un input type text.
Y en el valor, por ahora vamos a poner que esto sea vacío.
Y ya está.
Y con esto que tenemos el TD, data row.
En principio con esto yo creo que ya tenemos.
Lo importante es que no se nos olvide que todo esto tenemos que hacer un join.
¿Vale?
Con esto ya lo tendríamos.
El tr, body, html.
Claro, como veis aquí no hay nada, pero si le pongo aquí un 1.
A ver, si le ponemos aquí un 1.
A ver, ¿qué pasa aquí?
Otra vez el t-body.
Body.html.
Este sí que, ahora sí que se está llamando.
Ahora sí que se está llamando.
¿Por qué no he puesto este?
A ver, me falta algo.
A ver, este join lo tengo aquí.
Que lo estamos cerrando aquí.
Este join está bien.
Ah, claro, claro.
Porque esto, ojo, claro, claro.
Claro, fijaos.
Mira, es que es complicado.
Pensad en esto.
Esto es complicado.
Vale, el body.html este, claro, aunque en realidad debería al menos enseñarlo una vez, ¿no?
O sea, este body.html.
Es que estoy pensando que todo esto deberíamos hacerlo también por cada una de las filas.
Claro, si tenemos 10 filas, esto deberíamos repetirlo 10 veces.
O sea, no deberíamos ponerlo solo una vez.
¿Veis este row que he puesto aquí?
Claro, este row de donde lo saca.
Todos estos rows es porque yo estaba pensando, claro, tengo que dibujar el row.
Debe ser que está petando por esto, pero pongamos que esto es así, ¿vale?
¿Veis?
Ahora sí que aparece.
Claro, este row no sabemos qué row es porque tenemos que hacer, es que lo estaba pensando al revés.
Tendríamos que hacer que esto, primero, vamos a tener que hacer un range del rows y entonces para cada row, ¿vale?
Aquí vamos a poner row, vamos a tener que devolver lo que he creado, que sería esto.
Y ahora sí tenemos esto.
Ahora, esto, para que no aparezca esta coma, vamos a hacer un join con un espacio vacío.
Ahora, visualmente se ve fatal, pero lo importante, ahora visualmente se ve fatal.
Voy a quitar el 1 este que he puesto aquí para que se vea un poquito más como las celdas.
Pero ahora sí que se parece, ahora sí que se parece, ¿vale?
Ahora se parece más a un Excel.
Le faltan los estilos, que lo haremos.
No te preocupes que los estilos van a quedar bien finos.
Pero esto te dé sentido.
Lo que hacemos para crear el cuerpo es, vamos a utilizar el rango de filas y para cada fila vamos a dibujar esa fila donde siempre el primer espacio es este número.
Y después vamos a crear cada una de las celdas para que termine cada una de las columnas.
Estamos poniendo un span y un input.
Esto es importante porque, claro, luego veremos, igual que pasa en Excel, cuando...
Mira, voy a hacer una cosa con el Excel, con este Excel, ¿vale?
Google Spreadsheet.
No os puedo enseñar cómo abro el Spreadsheet porque os haría un spoiler, que no os quiero hacer el spoiler.
Pero es que hay un spoiler tan bestia en el Spreadsheet que sería una locura si lo veis.
Sería una locura.
Entonces, por ahora no...
Vale, pues fijaos.
Fijaos que cuando escribís sale una cosa.
Pero una cosa es lo que escribís aquí y otra cosa es lo que aparece.
Fijaos que son dos cosas diferentes.
Uno, el input, y otra, lo que aparece.
Entonces, digamos que necesitamos el valor calculado y el valor escrito.
Son como dos cosas.
El valor calculado y el valor escrito.
Parece muy complicado, pero bastante fácil.
Porque fijaos, este sería el valor calculado y este es el valor escrito.
Lo vais a ver más fácil si hago esto, por ejemplo.
Aquí aparece 4, pero fijaos que el valor escrito es igual 2 más 2 y el valor calculado es 4.
Entonces, vamos a hacer esto de tener por un lado el valor calculado y el valor escrito.
Y ahora lo verás muy fácilmente.
Entonces, vamos a arreglar un poco los estilos porque esto yo creo que es lo que va a hacer que tenga más efecto wow.
Vamos a ver si el border colapse.
Para que veis, para que los bordes colapsen, además que se queden más juntitos.
El t-head, vamos a ponerle un background diferente.
Vale, al menos lo vamos arreglando un poco.
El first child.
El first child sería este de aquí, ¿no?
O sea, del tr, la fila, la primera celda, el first child, pues sería este de aquí.
O sea, estaríamos quedando la primera celda.
Y esto, vamos a hacer que tenga el mismo color para que quede igual.
Vale, al menos hará una cosita así.
Podríamos ajustarle también que tengan el first child y el first child.
Vale, esto es para que este de la esquina, si no me estoy equivocando, a ver, tr, td, first child.
Vale, para que estos de aquí, este de aquí, todos tengan el mismo tamaño.
Entonces, al menos así, bueno, veo que no cambia.
Igual es porque, a ver, no, tampoco.
Pues igual, a ver, tr, tr, th first child.
Bueno, igual da igual.
Ahora lo centramos y ya está.
Vamos a hacer que las celdas, eso sí, tanto las de arriba como las de abajo, vamos a cambiarle el borde.
Vale, el input, vamos a quitarle el borde también para que quede mejor.
Vale, de repente, has visto al Excel, ¿eh?
De repente has dicho, hostia, al Excel, me cago en la leche.
¿De dónde ha salido este Excel?
Vamos a ponerle que esto, para que quite la fuente de esta negrita.
Vamos a poner que estas sean un poco más pequeñas.
Vamos a poner, no sé si poner que tenga un text align center, que tiene sentido.
Pero luego igual lo hacemos de otra forma.
Y a ver, ¿qué más podríamos hacer?
Vamos a hacer que las celdas sean más pequeñas.
No sé por qué, o sea, no sé por qué no me las pone.
Vale, el center ya lo he hecho y el vertical middle, ¿vale?
Hostia, ¿por qué no me está haciendo esto?
No me está pillando el tamaño.
Obviamente esto es alguna magia de las tablas, que si no, no pasa nada porque vamos a añadir más.
Pero esto, ¿ves?
No me está pillando.
Bueno, no pasa nada.
Cuando hagamos más, seguramente, o sea, si pongo aquí 5 o lo que sea, las hará más pequeñas.
Ah, no, las hace más pequeñas.
¿Por qué no lo está haciendo más pequeñas?
O sea, no me está haciendo...
Me falta aquí algún estilo.
¿Qué estilo me falta?
A ver, el que me lo diga.
Dale al children.
No, hombre, no.
Table layout fix, me dicen por aquí.
Pero esto habría que ponérselo a este.
No, no, porque tampoco me lo estaba pillando.
Inline block overflow.
¿Puede ser el input?
Puede ser el input.
Puede ser el input.
Sería raro, pero puede ser el input.
Mira, como el input, vamos a hacer unas cosas.
Vamos a ponerle opacidad cero para que no aparezca y solo aparezca cuando le demos clic al span.
Vamos a quitarle todo lo que sería aquí, todas las interacciones para que no se pueda utilizar el input.
Vamos a poner width 100%.
Vale, claro.
O sea, que es por culpa del input.
Claro, width 100% para que pille todo esto.
Ahora sí que si ponemos el first child este y el t de first child y esto lo hacemos más pequeño.
Ahora...
Ah, pues tampoco me está pillando...
Ay, perdón.
Esto debería ser tr...
No, trtd first child.
No, es que pensaba que este me debería pillar...
A ver...
Claro, es que me está pillando este.
O sea, es que quería pillar el primero para hacerlo más pequeño, pero tampoco me lo está pillando más pequeño.
A ver, vamos a ver este.
Vamos a ver este.
Ahora ya tenía claro que era el input, pero este...
trtd.
trtd first child.
Max width 20 píxeles.
Pues no me lo está pillando.
Bueno, da igual.
No pasa nada.
Tampoco es importante.
Obviamente es por culpa de este, pero quería asegurarme que podía hacerlo un poco más pequeño.
Bueno, no pasa nada.
El tema.
Son estilos.
No pasa nada.
Más o menos.
No quiero perder tampoco mucho tiempo con los estilos.
Ya tengo el input.
Una cosa...
Voy a hacer también el box sizing para que no me esté ajustando por culpa del padding y todo este tipo de cosas.
Y ya está.
Al menos ya tenemos esto.
Ya tenemos los estilos.
Nos faltaría hacer que las columnas sean letras.
Porque fijaos que aquí las columnas...
¿Veis?
Ahí A, B, C, D...
Son letras.
Y aquí empieza por 0, 1, tal.
Para hacer esto habría que ver el chart code.
Chart code.
El chart code básicamente es que cada carácter en JavaScript se puede saber que tiene como un código en concreto.
Y aquí podéis ver como los diferentes códigos que tiene cada cosa.
De 0 al 31, control characters.
El 32 es el espacio.
Bla, bla, bla.
Pero si seguimos bajando podemos ver que a partir del código 65 tenemos la A.
Entonces lo que podemos decir aquí es string from chart code 65 y esto te devuelve la A.
Y así que a partir de la posición 65 tenemos la B, tenemos la C y así constantemente.
Claro, otra cosa que podríamos hacer.
Pues nada, tenemos aquí letters y tenemos la A, la B, la C.
Pero no tiene mucho sentido hacer esto a mano.
Aunque podría ser, pero ahora mismo no tiene sentido.
Entonces en lugar de tener un array con todas las letras lo que vamos a utilizar es el rango este.
Es verdad que tendrá el límite de hasta qué número puede hacerlo.
Pero al menos programáticamente somos capaces de decir.
Vale, la primera letra empieza en la posición 65 y a partir de aquí vamos a recuperar las columnas, getColumn, donde le pasemos la I, string from chart code, first chart code más I.
Y así por la primera posición será el I será 0 y será la A y así constantemente.
Y este getColumn podemos ir al header aquí y en lugar de pintarla ahí, pintamos esto y ya está.
Ya tenemos las letras.
Bueno, no está mal, no está mal.
Preguntas hasta aquí que os voy contestando, amigos.
Y si quiero agregar la ñ, no, la ñ no es tan Excel.
Pero bueno, lo podrías hacer también, ¿eh?
Lo podrías hacer.
Justamente estoy también haciendo un clon de Excel, pero en mi caso uso grid.
Mira, lo he comentado que grid también sería una buena opción.
El range no lo entiendo, ¿vale?
El range, ¿qué es?
El range básicamente es para crear un array de X posiciones.
¿Para qué?
Pues lo hacemos básicamente para que quede mucho más declarativo.
Porque fíjate, cuando tú le dices range o yo qué sé, si en lugar de range le quieres llamar times, también lo puedes hacer, ¿vale?
Times puede ser un buen nombre.
Times quiere decir cuántas veces lo tiene que hacer, ¿no?
Pues cuántas veces tienes que hacer el, o sea, haz tantos rows como haya, haz este map, ¿vale?
Es una forma de simplificar el código para hacerlo como más declarativo.
Porque si no queda un poco raro tener que poner esto todo el rato o tener que hacer un for o un while aquí en mitad del código.
Como que lo hace un poco...
Entonces, por desgracia en JavaScript no tenemos una forma de simplificar esto.
Pero podemos utilizar esta construcción utilizando el array from que le pasas la longitud y aquí le indicas qué elemento tiene que ir dentro de cada posición del array.
Y fíjate que entonces esto, si tú le dices que length es 10, te crea un array de 10 posiciones con el 0, 1, 2, 3, 4, 5, 6, 7, 8, 9...
Y, hombre, está bien porque así tienes un array de tantas posiciones.
¿Para qué es esto?
Pues que resulta que si tú haces esto, te hace esas posiciones, pero ves que te hace todo undefined.
Y lo peor de todo, y esto es un poco tricky, que si tú haces esto...
Ah, pues sí que me funciona.
Ah, pues mira, pensaba que no...
Es que no me acuerdo.
No me acuerdo por qué esto a veces sea necesario.
Pero claro, en este caso nos va bien, aunque podríamos utilizar el índice.
Pero aquí nos va bien porque fíjate que lo estamos utilizando.
Está ahí, la estamos utilizando, este índice que estamos metiendo dentro, ¿vale?
Que lo estamos haciendo aquí como para rellenar cada posición con el índice.
O sea, es que ya lo estamos haciendo.
Esto es cómo queremos iniciar cada posición del array.
Entonces, si le decimos esto, le estamos diciendo que nos meta en cada posición el índice.
Y ya así lo tenemos perfecto.
Claro, como estamos utilizando el índice, fíjate, aquí lo utilizamos, el índice.
Aquí también, porque es el número de columna.
Entonces, por eso nos sale a cuenta utilizarlo.
Pero es una forma de simplificarlo y ya está.
¿Por qué input en lugar de content editable?
Pues en este caso, porque no tiene sentido.
Necesitamos dos elementos diferentes.
Lo he explicado antes.
Necesitamos un span para mostrar una cosa,
pero necesitamos un input para editar otra cosa.
Son dos cosas diferentes.
Yo creo que cuando lo hagamos, lo entenderán mucho mejor.
Porque si yo utilizo el content editable,
lo que vamos a tener es una cosa en lo que edito,
otra cosa en lo que muestro.
Y vamos a tener ahí como, ¿sabes?
Una colisión.
Y así lo evitamos totalmente.
Cuando hagamos esa parte, yo creo que lo entenderás mucho mejor.
Y para después de la Z, el AA.
Bueno, Laulo, en ese caso, después de la Z, el AA.
Esto puede ser un ejercicio interesante, pero es muy fácil.
Una vez que tenéis el getColumn aquí,
esta lógica ya la podéis cambiar.
Por ejemplo, si la i es mayor, que no me sé la letra, ¿no?
Entonces vamos a hacer otra cosa totalmente diferente, ¿no?
Podéis meter aquí lógica que haga algo distinto.
O sea, que aquí lo podéis arreglar.
Y yo creo que es un ejercicio interesante para que lo hagáis ahí.
Si es que si no, podemos estar aquí todo el día.
Así que ahí os lo dejo, ¿vale?
Para que lo tengáis.
Algo que nunca entendí bien fue la etiqueta SPAN.
Pues si el SPAN, el SPAN es el...
El SPAN es básicamente el DIP en línea.
DIP es para elementos que dividen el contenido y es del estilo bloque.
El SPAN es un DIP, pero que en lugar de ser de bloque, es de línea.
Por eso el SPAN se sube utilizar en el texto.
Porque es para las líneas.
Es para cualquier contenido que sea en línea.
En cambio, el DIP es para lo que es en bloque.
Pero semánticamente, el DIP y el SPAN son lo mismo.
Semánticamente.
Esa es la única diferencia, podríamos decir, ¿vale?
Por eso se utiliza para estilar textos, ¿vale?
Así que ahí lo tenéis.
Muy bien.
Pues vamos con más cositas.
A ver.
Ya que tenemos esto.
Claro, ahora las columnas son letras.
Tenemos que tener un estado, ¿vale?
Vamos a necesitar un estado.
Y lo vamos a crear aquí.
Vamos a poner un estado.
LetState.
Vamos a necesitar un estado para inicializar los valores de toda la tabla.
Entonces, vamos a hacer un range de todas las columnas.
Vamos a mapear que para cada posición de las columnas.
Vamos a devolver también el range de todas las filas.
Y esto se le llama matriz.
Ahora lo veremos cómo aparece.
Y aquí vamos a mapear y para cada celda, ¿vale?
Vamos a tener aquí cada celda.
Vamos a devolver un objeto que tenemos el computed value, que es el valor que hemos computado,
y el valor que tenemos que mostrar, ¿vale?
Y ahora veremos esto cómo queda.
A ver, aquí me queda este y este, ¿vale?
Y ahora pongo un console.log del state y lo vais a ver más claro.
¿Vale?
Ostras, espérate, porque aquí me está petando algo.
A ver qué me está petando.
En el range de computed value, range, a ver.
Esto lo estoy utilizando en su sitio correcto.
Vamos a quitar este, este por aquí.
¿Qué me peta?
Range, es que le he llamado range y es times.
Ahora estoy con el range, times.
Y además esto lo tenemos que hacer justo después, ¿vale?
No podemos utilizar times antes de que sea definido.
Vale, vamos a ver la consona.
Esto es una estructura de datos súper importante que tienes que dominar.
Si eres junior, trainee, perro, gato, marsupial o lo que sea.
Esto se le llama una matriz, que es un array de arrays, ¿vale?
Y en este caso, pues podemos ver que tenemos por cada columna 0, 1, 2, 3, 4.
Pues 0, 1, 2, 3, 4.
Y dentro de cada columna tendríamos el valor de cada una de las filas.
Esta sería la primera fila.
Esta fila que vemos aquí, esta de aquí, sería la que corresponde con esta.
Z, tu, ti, tu.
¿Vale?
Ahora lo vas a ver mucho más claro porque vamos a dibujar los valores.
Pero solo para que lo sepas que esto es súper importante porque cualquier tabla, cualquier tabla, cualquier casi videojuego, un montón de problemas de algoritmia, se utilizan muchas matrizas.
Así que aquí lo tienes que tener clarísimo.
Ahora que ya tenemos esto, ahora mismo no lo estamos mostrando, pero como tenemos esos valores, los vamos a mostrar.
¿Vale?
Voy a poner aquí que el value este sea la J, ¿vale?
J, que sería el índice de la fila, para al menos poner el valor y que lo podamos ver, ¿vale?
No es porque vayamos a utilizar eso, pero al menos ahí te va a ayudar a entender mejor cómo funciona esto.
Lo vamos a mostrar aquí.
Aquí vamos a tener el state.
Vamos a poner state.
Accedemos a la columna.
Accedemos al row.
Y aquí enseñaremos el computed value.
En el span, el computed value.
Y en el input vamos a tener en el value, vamos a tener lo mismo, pero vamos a tener en este caso el valor.
Porque va a ser el valor como real, digamos.
El valor que ahí haremos los cálculos y todo esto, que va a estar muy interesante.
Vale.
Aquí una cosa que veo es que el input...
Vale.
Veo que uno queda encima del otro.
Eso lo vamos a arreglar también.
Pero fijaos que tenemos aquí 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3.
Vale.
Porque estamos utilizando la J, que sería como el número de fila que determina lo que hay dentro de la celda.
Entonces, como estamos en la fila 0, la fila 1, la fila 2...
No confundir el índice de la fila con el número que aparece aquí.
Esto es porque en Excel, fijaos que empieza en 1, pero en los arrays y tal, ¿en qué empieza?
En 0.
Vale.
Entonces, es normal que aquí aparezca 0, porque estamos en la fila 0, aunque para Excel sea la fila 1.
Vale.
Entonces, ahora que ya tenemos al menos, que ya sabemos que los valores funcionan y todo esto,
vamos a añadir algunos estilos más.
Voy a hacer un position absolute.
Y para eso, aquí voy a añadir un position relative.
Aquí, position relative.
Y así, cuando en el span y el input le ponga que es un position absolute,
quedará uno encima del otro, lo vamos a centrar también, ¿vale?
Con inset 0.
El inset básicamente es decir que tanto a la izquierda como a la derecha, arriba y abajo,
estamos posicionando el elemento en el centro.
Si le decimos 0, es en el centro, ¿vale?
Estamos diciéndole, vale, todas las posiciones tienen que ser la posición 0.
Claro, si todas las posiciones tienen que ser iguales, significa que lo va a centrar.
Entonces, esto se puede utilizar en inset para eso.
Pero si no, podéis hacerlo así, pero es un poco más largo, ¿vale?
Pero es exactamente lo mismo hacer esto que hacer esto, para que lo sepáis.
Vale, vamos a vertical align middle, por si...
No sé si esto lo van a editar.
Si no, vamos a poner display inline flex.
Justify center, align item center.
Y ahora sí que lo tengo centrado, ¿vale?
Y podríamos poner, que claro, esto va a ser un poco más tricky.
Por ahora lo voy a intentar, a ver si cuela.
Si ponemos aquí que esto tenga foco.
Bueno, si no, luego lo arreglo, porque yo imagino que esto no va a quedar bien del todo.
Pero esto es para cuando tenga el foco.
A ver.
No.
No.
En el TD no va a colar.
Claro, podríamos hacer esto, ¿vale?
Pero esto lo haremos después.
Lo haremos después, ¿vale?
Lo voy a editar por ahora.
Vale.
Al menos ahora aparecen bien las cosas.
Lo que vamos a editar es mostrar el input a hacer el click.
Porque fijaos aquí, cuando tú estás en Excel, es verdad que en Excel es con doble click.
Nosotros lo vamos a simplificar.
Lo vamos a hacer con un click, más que nada para ir un poquito más rápido.
Pero bueno, te invito a que lo hagas con doble click y verás, a ver cómo lo podrías arreglar,
cómo quedaría y todo esto.
Se puede hacer sin ningún problema, ¿eh?
Entonces, vamos a hacer que al darle un click, aparezca el input.
Y cuando nos vayamos y le demos a otro sitio, pues que desaparezca y ya está, ¿vale?
Vale.
Pues vamos a hacer aquí, vamos a hacer algo.
Fijaos que las tablas, como las estamos pintando, son dinámicas.
Esto quiere decir que los elementos en el DOM no existen hasta que no se renderizan aquí.
Un error muy común es intentar añadir un evento a un elemento que no existe.
Porque, ojo, cuidado con esto.
Si tú intentas añadir un evento a un elemento que no existe, obviamente ese evento se queda en nada.
Y lo que es peor, cuando tú añades el elemento después, el evento por arte de magia no se junta, ¿vale?
Entonces, ¿qué es lo que podemos hacer?
Lo que podemos hacer son dos cosas.
Una, podríamos añadir los eventos aquí, justo después de renderizarlo.
Entonces, buscamos estos elementos y le añadimos los eventos.
Esa podría ser una, pero ya voy a dar un spoiler.
Vamos a tener que llamar a esta función de renderizar más de una vez.
Porque cada vez que vayamos haciendo cambios y como hay fórmulas que dependen entre sí,
vamos a necesitar volver a pintar todos los valores.
Claro, entonces, si yo voy añadiendo eventos y quitando eventos, es un poco rollo.
Entonces, la segunda opción, que también es muy típica en JavaScript, es el hecho de que podríamos utilizar como escuchar un evento en un elemento que ya existe,
pero que sea padre.
Y lo que hacemos es escuchar ese evento y luego observar si hay algún hijo que nos interese para ver qué es lo que tiene que hacer.
Por ejemplo, aquí dentro del render split sheet, yo había recuperado estos elementos tabla, head y body.
Esto lo voy a sacar fuera y lo voy a poner como en el cuerpo de la función para poder acceder a esto desde cualquier sitio.
Lo voy a poner aquí.
Lo tenemos aquí.
Perfecto.
Ahora podemos acceder dentro de esta función a esas variables porque están dentro del scope.
Y ahora aquí lo que vamos a hacer es, vale, pues voy a escuchar los eventos click del body,
de la tabla, en el cuerpo de la tabla.
Y aquí voy a hacer un console.log event.target, por ejemplo.
Lo bueno de esto es que ahora cuando nosotros vayamos aquí, si yo le hago un click aquí, podéis ver que está detectando,
que le estoy dando click a los spans que están dentro, aunque son dinámicos, porque no estamos escuchando el click en el span.
Estamos escuchando el click en todo el elemento del body.
Y ese elemento del body lo creamos aquí desde el principio.
Y así simplificamos un montón esto.
Lo más interesante es que una vez que ya estamos aquí dentro, podemos intentar sacar el elemento que estamos clicando.
Claro, aquí me dice el span, pero a mí no me interesa el span.
Yo creo, quiero recuperar este TD, ¿vale?
Para poder acceder desde aquí al input.
Pues lo que podemos hacer aquí es, primero, hacemos TD, event.target.closest.td.
Lo que estamos haciendo con este selector es, de el target que hemos añadido, o sea, que hemos recuperado el evento, que es el span,
búscame el elemento TD que esté más próximo para recuperar la celda de la tabla.
Ahora, aquí podemos decir, bueno, si no tengo TD, pues nada, salimos y ya está.
Pero si tengo TD, pues nada, dime qué TD es.
Y ahora, si le doy un click, fíjate que me ha devuelto el elemento TD.
Ahora sí, ya estamos en la buena ruta.
Además, tengo aquí también la posición X y la posición Y.
O sea, que ahora podemos recuperar todo esto del dataset, que para eso lo hemos sacado.
Dataset.
Podemos sacar también, podemos recuperar el input.
Podemos hacerlo desde el TD.
Esto también es una cosa interesante que mucha gente, o sea, que a veces la gente se vuelve un poco loca de cómo recuperar elementos.
Y es que fijaos que cuando tú recuperas un elemento del DOM, por ejemplo, aquí hemos recuperado el TD,
dentro no hace falta hacer otra vez document.queryselector y tal, sino que cualquier elemento del DOM puedes acotar la búsqueda y decir, vale, desde este TD, búscame el input.
Y así seguro que vamos a encontrar el input correcto, porque es del que estamos haciendo click.
Y lo mismo con el span, ¿no?
Podríamos tener span, queryselector y tal.
Y aquí ya, por ahora, bueno, podríamos ponerle un class list at editing, ¿vale?
Para dibujar esto un poquito mejor.
Pero lo importante es que si le doy click, pues no, peta.
Pues no funciona.
Class list at...
Ah, sí que funciona, pero he quitado los console logs.
He quitado los console logs.
Console log x y...
Bueno, console log x y...
¿Vale?
Vale.
Ahí tenemos el x y el y.
Vale, perfecto.
Y además deberíamos ver que está añadiendo las clases.
No las estamos quitando, ¿vale?
No estamos quitando como las clases.
Las estamos añadiendo todo el rato.
Pero bueno, eso lo podemos...
De hecho, no es necesario añadir la clase, ¿eh?
Ahora veremos por qué.
Lo que deberíamos hacer es, por un lado, tendríamos que mostrar el input.
Claro, deberíamos mostrar el input.
Pero ¿cómo hacemos lo del input?
¿Cómo quitamos...
¿Cómo ocultamos un input y hacemos...
O sea, deberíamos hacer un focus...
Vale, vale.
Ya sé qué vamos a hacer.
Vamos a hacer que cuando hagamos clic, hacemos un input.focus.
Y le vamos a cambiar los estilos al input.
Aquí.
Y vamos a decir que si tiene el foco...
Vamos a hacer lo que había pensado antes.
Vamos a hacer el outline que tenga los dos píxeles para que se vea.
Y podemos ponerlo del borde radius, que esto en realidad lo podríamos poner aquí para que estuviese siempre.
Y tendríamos que poner que la opacidad sea uno.
Para que cuando le demos clic y hagamos focus en el input, entonces aparezca.
A ver, vamos a ver ahora si le damos clic.
Vale.
Fijaos que ahora le doy clic y entonces me está añadiendo aquí, ¿vale?
Me está añadiendo como que ahora puedo escribir.
Lo quito y fijaos la diferencia entre lo que sería el valor para computar, que sería este, y el de mostrar.
Todavía no los estamos como relacionando.
Pero ahora ya tendríamos separados los dos valores, ¿vale?
Y fíjate que queda pues bastante bien porque parece que realmente cuando le das un clic, pues estamos cambiando la celda.
Una cosa es lo que enseña el span y otra cosa es lo que tiene en el input.
Os voy a enseñar un trucazo.
¿Queréis saber un trucazo?
¿Queréis saber un trucazo?
Porque esto, este trucazo, esto es ya para que lo sepáis.
Pero hay una cosa que a mí me da mucha rabia muchas veces en los inputs.
No sé si pasa aquí también.
Claro, fijaos.
Mira, mira, mira.
Esto es un trucazo.
Esto es un trucazo.
Vale, fijaos.
Cuando vosotros editáis en el spreadsheet del Excel, fijaos dónde os deja el cursor.
Os lo deja al final.
Pero nosotros, cuando yo edito, ¿dónde me lo deja?
Me lo deja al principio.
Y esto da bastante rabia, ¿vale?
Da bastante rabia.
Y esto se puede arreglar en JavaScript.
Para hacer eso, lo que podemos hacer es, vamos a recuperar la posición final.
Que la posición final en el input sería la longitud del valor que haya en el input.
Y le podéis decir que queréis como indicarle el rango, set selection range.
Le decís el rango del que queréis tener en el input al entrar, que queréis que esté seleccionado.
Claro, si le decís que el rango tiene que ser, la posición inicial es el final y la posición final es el final,
lo que vais a ver es que ahora te lo deja al final.
¡Anda!
¿Esto qué?
Esto no lo he visto mucho, la verdad.
Y esto es una pasada.
Esto está muy chulo.
Y os digo más, porque esto también está muy, muy chulo.
Imaginad que queréis que cuando entréis al input se seleccione todo.
Pues le ponéis set selection range.
Le ponéis el 0.
Y ahora cuando le deis un clic, está todo seleccionado.
¿Vale?
Así va del principio al final.
Y cuando entréis ya podéis escribir lo que sea y lo cambiáis.
¿Vale?
Por ejemplo, va...
Obviamente, a veces os puede interesar.
Depende.
En este caso yo creo que el comportamiento correcto, entre comillas, porque es el de Excel,
sería dejarlo al final.
¿No?
Y fijaos qué bien queda, que ahora lo dejan al final.
Esto está muy chulo, la verdad.
Es un trucazo porque...
Pienso que es mejor seleccionar todo al entrar.
Bueno, pero es que en Excel la gente estará más acostumbrada que te lo dejan al final, ¿no?
Yo creo.
Así que yo lo voy a dejar al final, pero bueno, si queréis, porque esté todo seleccionado y ya está.
Pero está muy bien porque es un momento y queda fino, fino, fino, mandarino.
Vale.
Ahora que ya tenemos esto, vamos a editar el valor del input para cuando entremos.
¿Vale?
Entonces vamos a utilizar...
A ver.
Aquí tendríamos el body...
Vale.
Cuando hacemos clic.
Lo que vamos a hacer es que cuando salgamos, eventListener, cuando hacemos el blur, el blur es el evento que ocurre cuando sales de un input.
Pues cuando salimos de un input, vamos a hacer un console.log aquí, donde vamos a tener el value, inputValue y el state, que va a ser state, x y punto value.
¿Vale?
Por ahora vamos a hacer esto.
Si el valor que tenemos es el mismo que el state que ya tenemos, o sea, si vamos a querer guardar lo mismo, hacemos un return y así evitamos cualquier repintado o cosa rara.
Pero si son diferentes el valor que ha introducido el usuario al que queremos poner, vamos a crear una función que sea updateSell, que le vamos a pasar la x, la y y el valor, que va a ser el inputValue.
Y os voy a enseñar otro truco muy interesante, porque claro, ¿cuántas veces queremos escuchar este evento?
¿Cuántas veces queremos escuchar este evento?
¿Cuántas veces creéis que tendríamos que escuchar el blur?
¿Cuántas veces ocurre?
¿Muchas?
No, muchas no.
Una, una, solo una.
Una porque ¿cuántas veces sales realmente del input?
Del input que estás editando.
En realidad solo estás, solo quieres editarlo una vez, ese input en concreto.
Por lo tanto, lo que podemos hacer aquí es utilizar las opciones, que tampoco se suelen utilizar mucho, que es esta, once true.
Y esto lo que va a hacer es que va a escuchar este evento una sola vez.
Tened en cuenta una cosa, este once true, esto lo podéis hacer con el click, con lo que queráis, con lo que queráis, ¿vale?
Lo podéis hacer, lo podéis utilizar con cualquier ad ever listener que queráis.
¿Por qué os digo esto?
Porque muchas veces he visto gente que para hacer el once true lo que hace es hacer un remove even listener a mano.
Que no está mal, pero es que esto te lo hace automático.
Esto automáticamente te va a hacer el remove even listener una vez que ya lo escucha.
Una vez que se ejecuta una vez, ya no necesitas hacer el remove even listener porque ya lo hace.
Once no, no es once veces.
Once significa en inglés una vez.
Y esto es otro trucazo.
Por eso creo que muchas veces es importante hacer proyectos con puro JavaScript porque se aprende un montón de cosas.
Y esta es otra, la de once, de hacer una vez un evento.
Esto muy poca gente lo conoce y está documentado, obviamente, no me lo estoy inventando yo.
¿Ves? Options, once.
Y aquí lo tenéis.
Hace mucho tiempo que se soporta, ¿eh?
No es una cosa que digas, no, es que la acaban de sacar.
No, es una cosa que ya tiene mucho tiempo.
Y está muy bien porque hay veces que tú quieres que solo se pueda aceptar una vez el click o solo se pueda escuchar una vez el evento, ¿no?
Para lo que sea.
¿Y eso para qué sirve?
Pues para lo que estoy comentando, para escuchar una vez el evento, para no tener que escucharlo varias veces.
Y así lo escuchas una sola vez y ya está.
Entonces, solo una vez podemos hacer el blur, solo una vez lo escuchamos.
Nos faltaría implementar este update cell que vamos a implementar aquí.
Vamos a hacer update cell, que le pasamos esto.
Para actualizar la celda, lo primero que vamos a hacer es tener un nuevo estado.
Y vamos a crear, vamos a utilizar otra cosa.
Esto sí que es bastante nuevo.
Va a ser el structure clone de JavaScript.
Bueno, no es de JavaScript exactamente, es de la web API, pero bueno.
Bueno, structure clone, ¿esto para qué sirve?
Structure clone nos va a hacer una copia profunda del array state.
Como el array state es una matriz que tiene un array de arrays y dentro de cada posición del array de arrays tiene un objeto,
vamos a hacer una copia profunda para evitar mutaciones y cosas raras.
En este ejemplo quizá no pasaría nada si lo mutamos realmente, pero lo quiero enseñar por si lo necesitáis para utilizarlo con React y cosas así, ¿vale?
Vamos a extraer la celda de la posición x y y vamos a computar, vamos a tener dos valores, ¿no?
O sea, en la celda tendríamos el valor, que es el que le pasamos desde el input,
y luego el valor que tendría que tener el span.
Por ahora voy a poner computed value, voy a poner algo sencillo, voy a poner number value,
que no es exactamente así, luego haremos cálculos y cosas así, ¿no?
Que tiene más sentido.
Pero por ahora voy a poner aquí computed value, number, y esto es lo que vamos a utilizar aquí, computed value.
Entonces, este sería el que muestra el span y este sería el que se queda el input, ¿vale?
O sea, que ya tenemos esa diferenciación ahí.
Vamos a guardar en el nuevo estado, en esta posición, guardamos esta celda otra vez con esta nueva información
y finalmente vamos a machacar el state con el nuevo estado, porque vamos a necesitar, obviamente, pues representar todo esto.
Y vamos a renderizar otra vez el spreadsheet.
Ahora, como tal, claro, necesitamos renderizarlo porque los spans tienen que cambiar, o sea, que eso es importante.
Pero esto veremos que después sí que es más importante.
Por ahora lo renderizamos y ya está.
Vamos a ver.
Voy a quitar todos estos números 0, 0, 1, 1, para que quede un poco más claro.
Aquí en el render spreadsheet vamos a hacer que aquí, ah, computed value, vale, en el estado inicial que hemos hecho aquí arriba,
aquí este state, veis que aquí ya había puesto j y tal.
Por ahora voy a poner 0, que todo sea 0, para que sea más fácil de determinar, vale.
Le doy un clic, vamos a poner aquí el 1, vale, y ahí tenemos el 1, vale.
Fijaos que ahora, pues ya ha cambiado correctamente esto.
Venga, le pongo el 2, voy a ponerle aquí el 3, vale.
Pues ahora podéis ver que se está renderizando correctamente y que ahí aparece eso.
Fijaos la diferencia que si yo no pongo esto, claro, esto no es React,
entonces si yo no pongo esto, fijaos que claro, yo escribo aquí, pongo el 2, salgo y me aparece un 0,
porque no estoy re-renderizando el span.
Esto es lo malo de utilizar JavaScript, que no tenemos como una forma de decirle,
oye, cada vez que cambio el estado, tienes que volver a renderizar esa parte de aquí.
Por eso muchas veces es importante React o otras bibliotecas como Vue y tal, ¿no?
Entonces, fíjate que aunque el input tiene el 2, claro, como no es capaz de saber que tiene que volver a renderizar el span,
podríamos hacer un control muy granular y decir, oye, cada vez que cambio este input,
entonces voy a cambiar también este valor.
Pero luego vais a ver que esto es bastante más complejo de lo que parece,
porque entended que luego vamos a tener fórmulas.
Vamos a hacer a1 más b1, ¿vale?
Y esto debería hacer una fórmula.
Entonces, claro, es un tema bastante complejo.
Así que necesitamos hacer el render, ¿vale?
Vale, vamos a hacer otro problema que he visto, es que cuando escribo, si le doy al enter, no pasa nada.
Entonces, vamos a hacer aquí, vamos a añadir un nuevo tu, tu, tu, aquí, input, input at event listener.
Vamos a poner que el input, si tenemos un key down, vamos a poner que esto, if event.key,
vamos a ponerle que sea, si es enter, input.blur, ¿vale?
Y ahí tendremos al menos que sea, ponemos aquí 3 y le damos al enter, me ha dejado fatal, punto blur,
antes listener, ta, ta, ta, a ver, if event key, vale, event key, esto está bien, ¿no?
Ay, esto está bien, pero no lo estoy, no me lo estoy ya trayendo, ¿vale?
Ahora sí, vale, ya tenemos el enter, al menos un poquito mejor.
Cálculos en las celdas.
A ver, una de las cosas que para hacer que Excel sea Excel, tendríamos que, si hacemos esto,
fíjate que ahora me pone NAN.
¿Por qué me pone NAN?
Me pone NAN porque este cálculo que estamos haciendo aquí, aquí está intentando hacer esto, ¿vale?
Y esto obviamente es NAN.
Entonces, aquí deberíamos hacer como una magia para calcular el valor que debería mostrar.
¿Cómo vamos a hacer esto?
Vamos a crear una nueva función, que vamos a llamar computeValue,
donde vas a tener, por ahora, el valor.
Y primero vamos a detectar si el valor lo tenemos que calcular.
Para eso tenemos que ver si el valor empieza con el igual, bueno, vamos a hacerlo al revés.
Si no empieza con el igual, entonces lo que hacemos es devolver el valor.
Esto significa que si empieza por el igual, es porque vamos a hacer una fórmula.
Esto es como funciona en Excel.
Si os fijáis, aquí en Excel, pues si tú pones igual uno más uno, ¿ves?
Me aparece dos, pero yo he escrito igual uno más uno.
Eso es porque ha entendido que con el igual hay que hacer una fórmula.
Entonces vamos a hacer un value, punto.
Si no empieza con un igual, devolvemos directamente el valor.
Lo que ahora necesitamos es el valor para usar, o podemos llamarle fórmula.
La fórmula sería el valor substring1, ¿vale?
substring1, ¿qué quiere decir?
Pues que se quede con toda la cadena de texto a partir de la posición 1.
Si estamos aquí y ponemos igual uno más uno, punto, tendríamos el de slice, que sería uno, slice.
substring, también sería otro.
substring, creo que también.
Es que hay muchas formas de hacer lo mismo, es un poco raro.
Bueno, porque creo que tienen más parámetros.
Creo que el único que deberíais evitar de los que os he enseñado, si no me equivoco, es el de substring.
El de substring, este, creo que este es el que hay que evitar, ¿vale?
Fijaos, aunque substring no es absolutamente obsoleto, se define el anexo que no lo deberíais utilizar, ¿vale?
Este es el único que digamos que habría que evitar, pero podríamos utilizar o el slice o el substring, el que prefiráis.
En este caso, vamos a poner el slice mismo, que es un poquito más corto y ya está.
Y aquí vamos a hacer un poco de trampa.
Podríamos instalar dependencias para poder hacer esto correctamente y tal.
Pero vamos a poner aquí, computed value.
O computed value.
Y vamos a hacer un try.
computed value igual eval formula.
Vamos a utilizar el eval.
Esto no lo hagan en sus casas.
Obviamente no es la forma, no es que no sea correcto como tal, porque al final, si estás controlando antes de hacer el eval, obviamente tendrías que intentar limpiar esto y todo esto.
Pero no es la mejor forma.
Hay un montón de dependencias, como por ejemplo save eval o hay sandboxes.
Hay un montón que lo que te hace es evitar los posibles problemas que te puede hacer el eval para hacer cosas así.
Pero en este caso, que en nosotros tampoco es muy importante, no pasa nada.
Si no sabes lo que hace eval, eval básicamente lo que hace es evaluar una cadena de texto.
Por eso es tan peligroso, porque si tú pones uno más uno del eval, pues te aparece aquí dos.
¿Qué pasa?
Pues que tú aquí puedes poner lo que te dé la gana.
Podrías hacer un fetch, podrías hacer mil millones de historias.
Además, normalmente el eval no se utiliza y no lo tenéis que utilizar en vuestro día a día.
A veces para calculadoras y cosas así sí que he visto que se utiliza, pero para información que el usuario pueda guardar y que cualquier otro usuario pueda acceder a esa información, obviamente hay que evitarlo.
De hecho, uno de los ataques más famosos de MySpace fue a través, si no me equivoco, no me acuerdo si fue un eval, no me acuerdo si fue un eval o es porque básicamente se podía ejecutar cualquier JavaScript por ahí.
Pero lo que hizo es en la descripción, mira, el Sammy Worm, puso un trocito de JavaScript y eso se ejecutaba y le enviaban una petición de amistad y así tuvo, fue la cuenta con más amigos del universo.
Pero bueno, en este caso ya no nos sirve.
Si el computed value nos da un error, voy a poner aquí error, que es algo parecido a lo que hace, creo que lo pone así, el Excel, ¿vale?
Le vamos a poner el message, al menos para saber cuál es el error.
Y de todo esto hacemos un return del computed value y ya está.
Lo interesante de esto, obviamente, esto normalmente es una prueba técnica en la que el tiempo es limitado y tendrías que explicarle, oye, voy a utilizar esto por esto y lo otro o intentar utilizar una dependencia que te haga exactamente lo mismo de forma mucho más fácil.
Pero al menos con esto, ahora este computed value que habíamos hecho aquí, vamos a llamar aquí computed value, le pasamos el value y ahora tendríamos que ver si esto funciona.
Si nos vamos aquí y ponemos igual 1 más 1, pues ya tenemos el 2.
Si le doy un clic, fíjate lo importante que decía de tenemos el input, que el input te pone 1 más 1, pero cuando sales, aquí te aparece un 2.
O sea, ya empieza a aparecerse cada vez más a Excel.
Lo bueno del Eval es que además podemos utilizar otras cosas.
Podemos utilizar cosas como esta.
Vale, casi.
MathPow, ¿no?
¿No es MathPow?
Ah, no, me acuerdo.
MathSum, no, MathMax, 1, 2, 3.
A ver si esto cuela.
Sí, sí que cuela.
¿No era MathPow?
Pensaba que era MathPow.
Igual me lo he inventado.
Pero fijaos que encima podéis utilizar las funciones de Math.
Está bastante chulo porque al final podéis utilizar las funciones de Math, podéis hacer cualquier cosa así, 1 más, MathMax.
O sea, podéis utilizar lo de Math.
Ahí súper bien.
¿Necesitas una Math?
Ah, porque necesita la base y el exponente.
Vale, gracias, gracias.
Vale.
Pero ahí podéis ver un poco la potencia, ¿no?
De que ahora ya podemos utilizar cualquier cosa ahí fácilmente.
Bueno, lo más interesante para saber o decir que estamos utilizando un Excel sería el referirte a otras celdas.
O sea, el hecho de decir aquí, aquí tengo el 1, aquí tengo el 2 y decir aquí, vale, pues esto es A1 más A2.
Vale, y peta, ¿no?
Y te dice error A1 is not defined.
Bueno, obviamente, esto también lo podríamos arreglar con un auto, ¿vale?
Para que no aparezca ahí todo.
Y creo que, no, pensaba que a lo mejor lo podríamos hacer scroll.
Estaría buenísimo.
Pero sí que se debería poder, a lo mejor aquí, auto o overflow auto.
Bueno, el tema es que, o scroll directamente, no sé si, claro, es que como no podemos, no se puede hacer.
A lo mejor tendríamos que fijar la altura para que estuviese también, bueno, eso ya lo voy a dejar para que lo hagáis, lo hagáis por ahí.
Pero hubiera estado genial poder hacer también el scroll para poder ver ahí el, se puede hacer seguro, ¿eh?
El tema es que nos dice que A1 is not defined, nos dice error, A1 is not defined.
¿Qué pasa?
Que, claro, nosotros estamos diciendo A1 más A2 y esto, cuando va al eval, aquí dice A1 más A2.
Y esto, pues, nos dice, reference error A1 is not defined, porque, obviamente, este A1 no existe.
Pero podemos simularlo.
Podemos simular que exista.
Podemos inyectar todas las constantes de todas las celdas de nuestra tabla
para que el eval pueda hacer esos cálculos perfectamente.
Y para eso, podemos crear una función que genere todas las constantes de las celdas, ¿vale?
Vamos a pasar aquí las celdas.
Y lo que vamos a hacer es iterarla, ¿vale?
Tengo todas las celdas.
Entonces, aquí tengo todas las filas.
Las filas, y esta sería la X.
De todas las filas, vamos a devolver, ¿vale?
Map.
Aquí tendríamos la celda y la Y, ¿vale?
Y ahora que tenemos de cada celda, esto sería una iteración típica de una matriz.
De que tenemos la matriz, vamos a ir primero como a por las columnas,
luego nos devuelve las filas y luego de cada fila podemos acceder.
En realidad he puesto aquí como cells, pero en realidad tendríamos...
Bueno, sí, cells tiene sentido porque nos devuelve las filas.
De cada fila tendríamos la celda y ahora en cada celda podríamos recuperar primero la letra
utilizando el getColumn que tenemos, le pasamos, ¿vale?
Tengo aquí la X, que esta sería la columna.
Entonces, primero tendríamos el índice, sería el 0.
Por lo tanto, la letra aquí, la primera sería la A, ¿vale?
Ya tenemos la letra.
Ahora tenemos que crear la ID de esa celda.
Tenemos la letra por un lado y por otro lado tendríamos que tener el índice de la fila,
que sería I más 1.
¿Por qué el más 1?
Porque el A0 no existe, es A1, ¿vale?
A1.
Así que por eso tendríamos aquí A1.
Ya tenemos como que estamos creando este A1 que hemos creado,
lo estamos haciendo en esta primera iteración, ¿no?
Y ahora lo que necesitaríamos es crear lo que tenemos que inyectar para crear aquí,
imagínate algo así, const A1 igual 1, const A2 igual 2 y que ahora esto funcione correctamente.
Fíjate, si nosotros hacemos esto const A1 y le damos el valor const A2, ahora sí que funciona.
Entonces, iterando esto, vamos a devolver const cel ID igual cel y le vamos a pasar el computed value, ¿vale?
De la celda el computed value.
No el valor normal que vemos, sino el valor computado, el ya calculado,
porque si le pasamos el del input, pues esto va a fallar.
Pero si pasamos el que muestra el span que ya es calculado, pues debería funcionar correctamente.
Entonces, con esto estaríamos creando estas dos líneas de aquí,
pero para todas las celdas que tenemos.
Importante que no se nos olvide aquí, pues otra vez, el join.
En este caso vamos a poner un salto de línea y aquí un salto de línea.
En realidad no es importante.
O sea, aquí lo que podríamos hacer con estos const, en realidad, es importante no dejar.
O sea, podríamos ponerlo así vacío.
Yo creo que con un salto de línea, sí, por si tenemos algún problema, lo veremos claro, ¿no?
Que sería como lo estamos haciendo así.
Podríamos poner el punto y coma también aquí para que no tengamos problemas
y le ponen algo con paréntesis y tal, ¿vale?
Como hemos hecho aquí.
Y con esto ahora podríamos llamar el generate, lo tenemos que llamar en el updateCell, ¿vale?
Aquí vamos a crear las constantes con el generateSelfConstants utilizando, bueno,
el newState o el estado antiguo, da igual.
Aquí tendríamos todas las constantes y estas constantes que hemos creado,
cuando computamos el valor, se la vamos a pasar como segundo parámetro, aquí.
Y en el computeValue, ahora que tendríamos aquí el evalFórmula y todo esto,
lo que vamos a tener cuidado es de crear un poco más de código.
Vamos a decirle, mira, vamos a crear una función que se autoinvoca, ¿vale?
Así.
Así y así.
Una función que se autoinvoca, básicamente, sería algo así.
Esto es una función que se autoinvoca.
¿Y para qué sirve esto?
Bueno, esto sirve realmente como para generar un scope en el que no van a, digamos,
a entrar en conflicto con las cosas que haya afuera.
No es necesario, tampoco es muy importante realmente aquí con el eval y tal,
pero sí que puede ser importante para evitar que entre en conflicto con el código
que ya estamos ejecutando, ¿no?
Entonces, ahora lo que vamos a poner aquí sea constante a uno, pues hola, bueno, hola.
Aquí tenemos que poner dos, consta dos, dos, y aquí esto es lo que vamos a querer conseguir, ¿vale?
Una función que se autoinvoca porque en cuanto la estás creando, esta función,
la estás ejecutando y te está devolviendo directamente el valor que está devolviendo aquí en la función.
Fíjate la diferencia que si no la autoinvocásemos, pues esto se quedaría así y te devolvería una función.
O sea, esto sería una función, pero como cuando la creamos la estamos invocando a la vez,
esto lo que nos devuelve es el valor.
Así que ese valor, lo que vamos a tener aquí, ¿vale? Esto sí que está bien.
Esto tendríamos así y esto aquí.
Y ahora aquí tendríamos, pues, las constantes que le estamos pasando por parámetro
y finalmente devolveríamos la fórmula.
No sé si tendríamos que devolver la fórmula.
Ah, sí, tenemos que devolver la fórmula porque ahora es una función.
Y con esto, en principio, ya deberíamos ser capaces de poner aquí, pues, un 2,
aquí otro 2 y aquí decirle, vale, pues, a1 más a2.
¡Y! Constance is not defined.
Vale, espérate, que la he liado.
¡Ah! Porque no la he puesto aquí.
No se lo he pasado por parámetro.
Vale.
¡Uy! ¡Uy! ¡Uy! ¡Uy! ¡Casi!
Venga, a ver ahora.
A1 más a2 y tampoco.
Porque aquí se me ha escapado algo.
Es que aquí...
A ver.
Es que este sobra, ¿verdad?
Porque esto...
¿Ves que me lo está poniendo...?
Yo juraría que se sobra.
A ver, aquí.
Sí, sí, sí, sí.
Sí, sí, sí, sí.
Sí, sí.
No sé por qué se está volviendo loco el...
Sí, sí.
¿Ves?
Mira que lo he visto, ¿eh?
Pero me ha dicho, no, no, que no sobra.
Y me he fiao.
Venga, a1 más a2, 5.
Ya está.
Entonces, ahora ya podemos empezar a hacer cálculos a 2 por a1 más más max, 1, 3, 9.
¿Vale?
Y le damos un clic y ahí tenemos pues toda la fórmula con todo lo que estamos haciendo.
Ahora, hay un problemita.
Hay un problemita.
Y es que si yo edito esto, claro, he editado esto y fíjate que al editar este no se ha actualizado este.
Que debería ser este, debería ser 6.
Porque a1 más a2 debería ser 6.
Y en cambio se ha quedado un 5 porque no ha detectado que este cálculo que hemos hecho ahora en a1 nuevo debería afectarle también.
Entonces, claro, el tema es que cada vez que cambiemos, actualicemos una celda, uy, perdón, cada vez que actualicemos una celda deberíamos también actualizar todas las celdas.
A ver, esto lo podríamos hacer mucho mejor.
Al final, esto es como, para hacerlo en el mínimo tiempo posible, pues actualizarlas todas.
Lo ideal podría ser observar o poder suscribirte a qué celdas son las que te interesan sus valores.
Y es una cosa que te dejo como ejercicio porque está bastante interesante.
Pero por ahora lo que podríamos hacer es, bueno, pues vamos a computar todas las celdas de cada una de las celdas.
Pues nada, volvemos a recuperar todas las filas.
Esto es otra vez lo mismo de iterar una matriz para cada celda.
Aquí tenemos la posición i.
Y aquí, pues vamos a recuperar el valor computado.
Vamos a valor computado con el value.
Le pasamos las constantes.
Y ahora vamos a actualizar el computed value de esa celda.
Y esta función la tenemos que llamar justamente antes de volver a renderizarlo.
Aquí, en el update cell, antes de volver a renderizar toda la tabla, aquí tendríamos que pasarle.
Podríamos pasarle el state, constants, que en realidad aquí es donde está un poco el tema.
Porque igual esto tendríamos que hacerlo así, en realidad.
State y esto aquí así.
O sea, este state debería ser lo último que actualizásemos.
Esto es lo que tendría sentido porque aquí este new state, aquí también se está modificando, se está mutando y tal.
Entonces debería ser solo en este punto.
Y con esto ahora, si ahora ponemos el 2 aquí.
Ponemos el 2.
¡Ay!
La he liado.
Espérate.
Si ponemos el 2, ¿qué le pasa?
Value.startsWith is not a function.
Vale.
Value.startsWith is not a function.
O sea, me está diciendo que el value en algunos puntos, claro, porque no está recibiendo un string.
Claro, no siempre es un string.
Tiene sentido.
¿Ves?
¿Ves?
Me devuelve cero.
Entonces, aquí lo que podríamos hacer es que si typeof value es igual a string y además empieza con esto, no empieza con esto.
Si el typeof value es un string y no empieza con esto, entonces devolvemos esto.
A ver, a ver si esto tiene sentido.
No.
Slice is not a function.
Si es diferente...
A ver, hay cosas que podemos hacer.
Si es un string...
Si es un string, vamos a querer directamente...
Ah, no.
Si es un string, no.
Claro.
Primero tendríamos que ver esto.
Claro.
Que si es un número...
Es que deberíamos...
Typeof value.
Si es un number...
Devolvemos el valor.
Si es string y es diferente a esto...
Vale.
A ver ahora.
Vale.
Dos.
Aquí el tres.
Aquí hacemos a uno más a dos.
Y aquí cambiamos esto.
Y no lo ha hecho.
Se nos ha escapado algo.
Vale.
Ahora lo miramos.
A ver qué.
Mientras os voy a leer.
En A3 rompe algo diferente a string o empieza por...
O empieza por...
Si es diferente...
No.
Esto debería estar bien, ¿no?
Typeof value diferente a string o...
A ver.
A ver.
Esto igual lo puedo quitar, ¿eh?
Ya.
Porque ahora ya no tiene...
No tiene más.
Pero ahora lo arreglamos.
Repro este directo.
Gracias, ¿eh?
Miro, no has pasado la prueba técnica.
¿Te imaginas?
Joder.
A ver, ¿pero cuánto llevamos?
Si solo llevamos una hora y media.
Dame.
Dame a arreglarlo.
Dame a arreglarlo.
De manera primitiva con Observer se puede hacer con el Observer.
¿Qué Observer?
Observer.
¿Cuál te refieres de Observer?
Con el Mutation Observer.
Con el Mutation Observer podrías hacer alguna cosa.
Podrías hacer alguna cosa.
Pero toda...
Toda...
No.
Vale.
A ver.
Tenemos este.
Tenemos este.
A1 más A2 y...
Cinco mesesitos ya aquí.
Conseguí mi primera chamba.
Ah, qué grande, Midu.
Me cambiaste la vida.
Gracias, amigo.
Muchas gracias.
Bueno, pues todavía tenemos el problema.
Tenemos el problema y estoy pensando a ver cuál puede ser el problema.
Porque en realidad Compute All Cells.
Esto lo estoy llamando aquí con el New State.
Estoy pasando las constantes.
Aquí deberíamos estar calculando esto.
Aquí en Computed Value.
Aquí tendríamos la celda que estamos mutando del nuevo estado.
Aquí machacamos el nuevo estado.
Aquí las constantes.
Bueno, a ver.
Mientras...
Mira con celda del estado a ver qué tiene.
A ver.
Si en una celda anterior utilizas una celda que está después y esta tiene una forma,
¿no sea un problema?
No.
¿No se está renderizando el value?
No creo que sea eso.
A ver.
Vamos a ver.
El State.
Una vez que se actualiza esto.
Y este Compute All Cells.
Lo estamos llamando bien, ¿no?
Tenemos la X.
Compute Value.
Es que me da la sensación...
No, pero es que esto debería estar bien.
Dice...
Si no empieza...
Devolvamos el valor.
A ver.
Vamos a ver.
Vamos a ver aquí...
Buah, que cuando tengamos esto ya...
Además, luego os quiero enseñar cómo seleccionar una columna entera.
Que eso está brutal también.
Entonces, esto funciona bien.
Aquí, bien.
¿Vale?
Tenemos el 5.
Y aquí podemos ver, pues, a 1 más a 3.
Compute Value 5.
El problema está que cuando cambiamos esto,
obviamente...
Obviamente.
Aquí, Value.
Vale.
Y aquí no me está computando...
¿Ves?
Compute Value.
Me estaba dejando el 5.
Compute Value me está dejando el 5.
Y este 5 debería haber pasado a ser 6.
Compute Value.
Value.
State 2.
O sea, no me lo está pillando.
Cuando renderista tiene una función, habría que agregarle un Everlisten
y actualizar a celdas que la usan función.
¿Dónde está mi suposición?
¿Te torna un número o un string?
Eso da igual porque realmente...
Que sea un número o un string, eso da igual porque realmente los estamos transformando.
Y cuando hacemos en el Everl son cadenas de texto que ahí se calcula.
O sea, que en eso no habría ningún problema.
El problema es que esto deberíamos llamarlo...
Y se debería estar llamando esto aquí.
Esto es normal, que no haga un return.
No pasa absolutamente nada.
Vamos a poner aquí Compute All Cells.
A ver si esto se está llamando.
Y a ver aquí Console Log.
Vamos a poner aquí un Console Log.
Con todo esto.
Lo vamos a poner al final para ver si se está calculando.
Venga, vamos aquí con el 2.
Vale, este de fuera.
Fuera.
A 1, a 2.
Hasta aquí bien.
El problema lo tenemos aquí.
Cuando ponemos el 3, que se queda en 5.
Y fijaos que esto debería ser 0, 1, 2.
Aquí, en el 0, 0, tenemos el 3.
Aquí tenemos el 3.
Y aquí me ha dejado el Computed Value con 5.
Pero me ha puesto este Value.
O sea, esto sí que lo está haciendo.
Aquí lo tenemos bien.
Porque fijaos que aquí tenemos el Computed Value con 3.
El Computed Value con 3.
O sea, estos valores están bien.
En cambio este, este aquí, cuando le decimos Compute Value y le pasamos el punto Value y las constantes,
aquí este Compute Value, claro, dice si el valor es un número, devuelve el Value.
Si el valor no empieza por esto, hace esto.
O sea, aquí realmente debería estar haciendo toda esta cosa.
Pero no parece que la está haciendo.
Computed Value.
A ver, aquí debería llegar solo una vez.
Claro, las constantes, las constantes, las constantes, claro, las constantes, ¿qué?
Las constantes debemos generarlas otra vez.
Ya está, ya está.
Ay, pero qué interesante, ¿eh?
Es que es difícil.
Al final es difícil.
Claro, las constantes hay que generarlas otra vez.
Ahí está.
Estas constantes hay que generarlas otra vez, una vez que se han hecho todos estos cambios.
O sea, estas constantes, la primera vez para hacer los primeros cálculos y luego la segunda vez para computar todas.
Porque esas constantes han cambiado ya.
Han cambiado.
O sea, que tremendo.
Oye, Jesús Robot, muchas gracias por regalar 10 suscripciones.
5 meses ya aquí conseguí mi primera chamba.
Qué grande miedo me cambiaste la vida.
Jesús, nos has traído buena suerte.
Gracias por regalar 10 suscripciones, amigo.
Te lo agradezco infinito.
Tremendo.
Gracias, gracias.
Qué crack.
Muchas gracias y me alegro muchísimo por ti.
Mucho, mucho, mucho.
Pues ya está.
Es esto.
No tengo pruebas, pero tampoco tengo dudas.
Ya está, ya está.
Pero es que claro, ahí está el tema.
Ahí está el tema.
Ahora sí.
Fijaos, ponemos 2.
Ponemos 3.
Ahora sí, ahora sí.
Ahora sí.
No me dejes mal que te reviento.
Te reviento.
3 y ahí tenemos el 6.
Ahí tenemos el 6 y el 3 aquí.
Y podemos decirle a 1 más a 2 más a 3 más a 4.
Y aquí le ponemos a 4.
Y ahí van cambiando los números.
Y esto es una maravilla.
Y todo cambia.
Y todo funciona.
Y todo perfecto.
O sea que tremendo.
Ya está.
Ahora sí que se pueden ver que todo lo que son cambios que además están relacionados,
pues funcionan correctamente.
Así que ahí lo tenemos.
Y aquí por lo mismo.
Podríamos decirle a 5 más a 4.
¿Veis?
Y ahí lo tenemos.
Bueno, bueno, bueno.
Vale.
Genial.
Vale.
Ahora sí.
Ahora sí.
Menos mal.
Menos mal.
Vale.
Pues os voy a dejar ejercicios, pero os quiero enseñar, claro, una cosa que es interesante
de Excel es el hecho de que puedes hacer esto, pum, y seleccionar una columna entera.
Y esto está interesante.
Está interesante porque, uno, para verlo visualmente.
Dos, porque puedes hacer esto y se borran todas.
O puedes copiarlas todas.
O sea, podrías hacer, claro, seleccionar así es más complicado.
Pero seleccionar así y copiarlo y pegarlo en algún sitio y tener esto, esto lo vamos
a hacer.
Porque me parece muy, muy interesante y es llevarlo como al siguiente nivel y es tremendo.
Entonces, lo primero que vamos a necesitar sería como un flag por aquí, que sería Selected
Cell.
No, Column.
¿Vale?
Porque vamos a trabajar con la columna.
¿Vale?
La Selected Column.
Y aquí, igual que teníamos un ATV Listener para el body y tal, vamos a tener uno con
el head, ATV Listener, que cuando le hagamos un clic, pues vamos a tener un evento y vamos
a hacer lo mismo.
Vamos a mirar que estemos en un TH, vamos a recuperar la celda de la cabecera que esté
más cerca.
Si no tenemos, hacemos un return.
Y ahora vamos a recuperar para saber.
A ver, podríamos hacer dos cosas.
Porque podríamos hacer lo del dataset, pero te quiero enseñar una forma más avanzada
de cómo recuperar, cómo saber cuál es el índice de lo que estamos clicando.
O sea, si yo le doy clic aquí, ¿cómo sé que le he dado a la columna número 1?
Porque esta sería la 0, esta sería la 1, la 2.
¿Cómo lo podríamos saber?
Bueno, pues es un poco más avanzado, pero está interesante.
Podríamos desde el elemento, podríamos desde el elemento recuperar el padre, recuperar
todos los hijos y de todos los hijos convertirlos en un array, porque esto te da una lista de
elementos del DOM y sacar el índice del elemento que hemos clicado.
Con esto, que así parece un poco complicado, pero mira, lo vamos a ver más fácil.
Fíjate que tengo aquí este TH, está la A.
Si vamos a la consola y ponemos $0, fíjate que el $0 se refiere al elemento que tenemos
seleccionado.
$0.parentNode, ¿vale?
Sería todos los elementos que tenemos en la cabecera, ¿vale?
Todos los elementos.
Si ahora aquí buscamos los children, esto me da una colección de HTML, que son todos
los hijos que tenemos ahí.
Si esto lo transformamos en un array, pues ahora tendríamos un array con los 6 elementos,
¿vale?
Y si ahora buscamos aquí cuál es el índice del 0, el que teníamos seleccionado, ahora
me va a petar porque no tengo ninguno seleccionado, pero selecciono este, vuelvo a la consola
y tampoco me va a funcionar.
No sé si me va a funcionar, no me va a funcionar porque no funciona lo del índice o porque
find index.
Debería funcionar, pero claro, es que no sé si es que no se puede utilizar más de una
vez aquí y tal.
Pero bueno, esta es la lógica que estamos utilizando.
Vamos a ver si aquí no funciona, que yo creo que sí que no funcionará.
Y esto nos debería dar la X, ¿vale?
Como en lo que hemos, la columna en la que hemos clicado.
Obviamente, si nos da un número menor a 0, pues es que no existe.
Así que vamos a hacer un return, así nos evitamos problemas.
La selected column, la columna que estamos seleccionando va a ser X menos 1, ¿vale?
Porque, a ver, si nos da la columna, claro, si nos da la 1, que será esta, esta sería la
1 porque es la columna 1.
Pero en Excel no existe la columna 0.
O sea, esta columna no existe.
Por lo tanto, vamos a tener que hacer que, para nosotros, la columna 1 en el índice de
los arrays sea la 0 porque es como empezamos a contar.
O sea, en los arrays esto sería la 0, la 1, la 2, la 3, la 4.
Cuando hablamos de la columna 1, para nosotros estamos hablando de la columna 0.
Excel dice columna 1, nosotros en arrays, columna 0, ¿vale?
Y aquí vamos a seleccionar, vamos a seleccionar, es que aquí os va a volar la cabeza porque
esto es todavía más complicado.
Vamos a seleccionar la fila con el, no, el TR, sí, TR, T, D, N, T, C, Child con el número
de la selected column, selected column.
Lo que pasa es que en CSS, y esto es lo que va a ser un poco tricky, en CSS tendríamos que
quedarnos con la X, pero además deberíamos sumarle 1, y ahora veremos por qué.
Pero por ahora voy a ponerle una X para que lo veamos, ¿vale?
Y para cada elemento que tendríamos ahí, cada elemento, vamos a añadirle una clase que
sea selected, ¿vale?
Esto es un poco tricky porque vais a ver que los índices son un poco de aquella manera.
Entonces, vamos a añadir los estilos para que veamos a ver si esto funciona correctamente.
Vamos a poner aquí selected, vamos a tener un background con un color, voy a modificar
este color, vamos a poner que tenga, no sé si ponerle que tenga esto o que sea más
bien algo así, ¿vale?
Y podríamos poner que el TH.selected, vamos a ponerle un background un poco más fuerte,
que esto también es como funciona en Excel, ¿vale?
Que si os fijáis aquí en Excel, el de arriba como que tiene un azul más fuerte, ¿no?
Vale, fijaos que le he dado, le he dado, y me ha puesto el de al lado.
Entonces, por eso os decía que este NTH child tiene que ser más 1.
Y esto es porque tenemos, estamos trabajando con tres índices diferentes.
Los arrays para nosotros que empiezan en 0.
Por otro lado, los de CSS, que está hablando de el número del hijo.
Y por otro lado, en Excel, que empiezan por 1, o sea, es una mezcla.
Pero ahora sí, con esto, y podremos poner también aquí que este TH class list add selected,
y ahora sí tendríamos seleccionada esa.
Obviamente no estamos quitando ninguna, así que lo que tenemos que hacer es detectar todo lo que sea selected
y quitar los selected antes de poner más.
Y ahora al menos ya lo tendríamos así, perfectamente, como toda la columna estaría como seleccionada.
Lo bueno es que una vez que ya tenemos como seleccionada la columna,
podríamos añadir, por ejemplo, borrar todos los valores que en el documento cuando le demos a la tecla
backspace, que es como la de borrar, creo que es backspace en minúscula, backspace, ¿vale?
Y la select column es diferente a null, o sea, que tenemos una columna, está seleccionada.
Lo que vamos a hacer es, bueno, podríamos hacer un for, podríais hacer lo que quieras.
Yo voy a utilizar el for each, aunque podéis utilizar el que queráis.
Entonces, para todas las filas que tenemos, claro que el rows estoy pensando, claro,
lo que tendríamos que hacer es un times, o sea, para hacer esto, porque no tenemos el rows,
tendríamos que hacer times rows, y para cada row, entonces tendríamos que empezar.
Ya tenemos la columna, por eso no necesitamos iterar la columna, solo necesitamos las filas.
Tenemos que decirle, vale, quiero que me actualices la celda de la columna seleccionada de la i y le pones
el valor, que le podemos poner el valor que queramos, ¿vale? Y con esto ya lo tendríamos.
Lo que pasa es que cada vez que borremos valores, vamos a, bueno, podríamos quitar lo de la columna seleccionada,
esto da igual realmente, pero lo que sí que es importante es que hay que volver a renderizarlo todo,
porque si no, no se reflejarían. Entonces, si le damos aquí, ¿ves? Ya lo tenemos aquí,
y ahora pues podríamos volver a escribir y tal. Ahora el problema es que fíjate que no me deja escribir,
tendríamos que ver a ver qué le pasa ahí, pero bueno, eso lo veremos después.
Por ahora ya, al menos que lo tengamos aquí eliminado.
El problema de que no me deje escribir y esto es, seguramente, por los valores vacíos y tal,
que no los hemos estado cuidando mucho, tendríamos que hacer algún if ahí de,
oye, si esto es vacío, pues lo tienes que ignorar, o cuando hagas una computación,
ten en cuenta que los valores vacíos, pues me cuenta por cero, o incluso que me puedas dar un error,
o lo que sea, esto te lo voy a dejar de ejercicio también para que lo puedas hacer,
pero el que me gustaría sí hacer sí o sí, para que lo veas, es el hecho de que imagínate
que tenemos aquí, hostia, es que ahora me está, ah, espérate, es que esto no es de esto,
esto a lo mejor, es que esto lo he puesto mal, esto está aquí, el problema,
el problema es que me está volviendo a renderizar, ese es el problema.
No, no, el problema este de que se eliminaban y que no me dejaba escribir
era porque había puesto el render fuera, ya está, ya está.
Pero igualmente aquí sí que vamos a tener problemas si intentamos hacer algunas sumas
o lo que sea, y hay un valor vacío, seguramente ahí petará y dirá,
hostia, pues aquí no lo puedo usar por esto, ¿no?
Habría que hacer que cuando es vacío, pues o lo ignore o lo que sea.
Lo que os quería enseñar, el copy-paste, ¿vale?
¿Cómo podemos hacer? Copiar una columna entera.
Eso es súper interesante porque lo que podemos hacer aquí es,
igual que aquí cuando hacemos y seleccionamos una columna,
copiamos y podemos pegar todos los valores,
fijaos que tengo aquí como todos los valores de la columna,
esto mismo lo vamos a poder hacer y además con un evento.
Y así vas a aprender que también puedes escuchar el evento de copiar
y no se hace como mucha gente hace,
que con el keydown se pone a ver si está copiando con el atajo.
Existe un evento nativo que se llama copy,
que podéis utilizar para detectar cuando el usuario está intentando copiar algo.
Entonces aquí, por ejemplo, ¿ves? Vamos a poner copy.
Vamos a poner aquí, si le damos aquí y le doy a copy, ¿ves? Copy.
O sea, ya he detectado que ha hecho un control-c,
que estoy haciendo el atajo de copiar y cada vez que copio ya está entrando ahí.
Es que esto, no sé, mucha gente hace cosas muy raras de escuchar en el teclado,
si estoy haciendo el atajo o este y lo otro.
Bueno, pues hay una forma mucho, mucho más sencilla.
Entonces, si tenemos la columna seleccionada, ¿vale?
Si es diferente a null, lo que podemos hacer es tener aquí todos los valores de la columna
y igual que antes, pues timeRow, para cada fila, lo que vamos a hacer sería...
Bueno, aquí podríamos incluso hacer un map, o sea, más fácil todavía.
El columnValues, columnValues, ¿vale?
Lo vamos a hacer en un map y para cada row, pues vamos a tener aquí el state
con la columna, con la columna, con el row, con el computedValue,
no con el value, que el value es el que tenemos en el input, con el computedValue.
Esto lo devolvemos y con esto, pues ya lo que podríamos hacer es copiarlo realmente
en el clipboard data.
Podemos tener aquí...
Podríamos, si queremos...
Bueno, con esta información es suficiente.
Podemos poner el clipboard data, set data, como texto plano, todos los valores con un salto
de línea, ¿vale?
Y ya podemos hacer un prevent default para evitar que haga la copia nativa, para que no
haga el copy que haría el documento, ¿vale?
Entonces ahora, si aquí tenemos el 1, y aquí tenemos el 2, y aquí tenemos el 3, y aquí
tenemos hola, y le damos aquí, copiamos y lo pegamos, fíjate que tenemos aquí
todos los valores copiados, y acabamos de hacer exactamente, exactamente lo mismo, lo
mismo que tiene el Excel, ¿eh?
O sea, exactamente lo mismo.
Podemos ir a otra, ¿vale?
Y vamos a otra, y aquí nos dará todos los ceros.
Le damos aquí, y estamos haciendo...
Bueno, aquí no tiene mucha historia, pero sí vamos a cambiar...
Hostia, lo he borrado.
Perdón, lo he borrado.
Pero lo importante es que ya tenemos aquí lo de copiar perfectamente en un momentito.
Fíjate que estamos copiando como todos los valores.
Ejercicio.
Pues hacer lo mismo con las filas.
Igual que lo tenemos aquí con las columnas, esto mismo se podría hacer con las filas.
Ahora mismo, pues hay un error porque ahí seguramente hay algún evento que escucha que no debería.
Pues hacer exactamente lo mismo con las filas se puede hacer sin ningún problema.
Lo que podemos hacer también, otro problema que hay es que aquí en Excel, cuando tú clicas cualquier otro sitio...
Bueno, es verdad que es un poco raro porque clicas otro sitio...
Bueno, cuando clicas otro sitio, desaparece, digamos, la selección de la columna.
Aquí, por más que clicas, no desaparece.
Para arreglar eso, podríamos poner otro documento, AventListener, con que tenga un clic,
y vamos a detectar, vamos a recuperar el target de aquí con el event.
Podríamos detectar si el TH ha sido clicado y así, pues vamos a mirar si está cerca de un TH
o si está cerca de una celda.
Entonces, si está cerca, si no está cerca de una celda y no está cerca del TH, del head,
pues vamos a recuperar todos los selected, le quitamos el class name y además el selected column
lo pasamos a null.
Y así con esto, si no hemos hecho nada raro, seleccionamos...
¡Ay! He escrito mal aquí el close esto.
¿Vale? Seleccionamos...
¿Veis? Ahora podemos seleccionar y podemos irnos a otro sitio.
Bueno, aquí... Ahí deberíamos hacer a lo mejor algo...
Claro, porque ahí, fijaos, que está detectando que estamos cambiando también esto.
Esto podría ser interesante también, como esta lógica que hemos puesto aquí,
extraerla en una función, de forma que, obviamente, si nos vamos a poner a evitar un input,
¿no? Si vamos a hacer esto de cuando hacemos el clic y lo vamos a hacer un focus,
pues obviamente deberíamos evitar también esto, de que si hacemos aquí y nos vamos a otro sitio,
¿no? Pues lo quitamos y ya está. Así que con esto tendríamos nuestro pedazo de Excel con JavaScript puro.
¿Tienen preguntas, amigos y amigas? Podéis hacer con el doble clic sin ningún problema.
80.000 líneas de código. Hombre, tampoco eso, ¿no?
¿Vido cómo funcionan las diferentes maneras de pegar sin... con formatos, solo valores o con el copy?
Bueno, ahí le podéis poner... le podéis poner aquí los diferentes formatos que queráis.
En este caso, creo que tiene sentido que sea de texto plano y yo creo que en Excel funciona exactamente igual.
O sea, por más negrita, por más colores que tenga esto, si yo copio toda la columna, pues me sale en texto plano.
O sea, ¿tiene sentido? No sé si se podría hacer... Claro, ¿ves? No se puede parar que cubre...
Entonces, yo creo que con texto plano, pero se podría hacer con HTML y tal, ¿eh?
Querido Mido, no entendí nada. Vaya, demons, pues hay que estudiar mucho, ¿eh?
Excel en la web. Me pidió hacer eso en el año 2006 cuando estaba aprendiendo a programar y mi respuesta fue eso es imposible.
Bueno, impossible is nothing. Joder, Mido, dedicando una semana te creas un Excel completo.
No, porque el problema que tiene el Excel y todas las cosas, todas las aplicaciones y tal, es que cuanto más te acercas al final, más complicado es.
Cada vez es más, más difícil. ¿Te faltan los macros? Sí, sí, ya te digo.
Ya te digo. ¿Está mal si manejo frameworks de JavaScript y no sé JavaScript de este nivel?
No, porque la verdad, amigo, es que no eres el único. Hay mucha gente allí fuera que trabaja con frameworks y no tiene JavaScript a este nivel, ni de broma, vamos.
O sea, que hay gente que utiliza frameworks por encima de sus posibilidades.
Mido, hace poco me llegó tu libro de Git. Muy bueno. Muchas gracias. Pues al día. Muchísimas gracias. Me alegro un montón.
Espero que te guste. Y si te gusta, no solo a ti, sino a cualquier persona que tenga el libro de Git, me ayudáis un montón si le dejáis una valoración.
Si lo tenéis, si os ha gustado, por favor, dejadle cinco estrellitas y le dejáis una valoración, le hacéis una foto y tal, que me ayuda un montón.
Me ayuda un montón. ¿Está mal que trabaje con frameworks de JavaScript sin saber casi nada de JavaScript?
Mal no está. Mal no está. Pero yo creo que es una cosa importante el hecho de que estudies JavaScript porque saber JavaScript solo puede ser bueno.
Un montón de cosas que te van a salir mejor. O sea, así de claro.
Menos mal, ya me sentía por no entender todo esto. Hombre, todo, todo. Yo entiendo que algunas cosas no las podáis entender, pero sinceramente creo que hay cosas que sí que las deberíais entender y si no, pues hay que echarle un vistazo.
Nunca se deja aprender. Yo usando frameworks, pero la necesidad lo lleva a uno a aprender directamente cosas nativas de la web. Bueno, totalmente. Es que tiene que ser.
Mira, dice, haz la suma por rangos. Eduardo. A ver, Eduardo, yo creo que ahora lo importante, porque yo puedo estar todo el día añadiendole features y tal.
Yo puedo estar todo el día, todo el día. Pero no se trata de lo que haga yo. Se trata también de que hagáis vosotros. Por ejemplo, hacer la suma por rangos.
No es difícil. Si es que al final, una vez que ya habéis visto todo lo que hemos hecho hoy, el rango al final es una cosa que tendríais que detectar cuando se quiera hacer un rango y hacer un for each y ya está.
O sea, es así de sencillo. También seleccionar por celdas. Poder seleccionar más de una celda a la vez, como hemos hecho con las columnas, también se puede hacer perfectamente con todo lo que habéis aprendido.
Añadir la funcionalidad. Añadir la funcionalidad de filas. Porque igual que hemos hecho esta de columnas, se puede hacer por filas perfectamente y es un momento.
Funcionalidades. Yo creo que aquí es donde tenéis la oportunidad de que habéis visto el vídeo, habéis hecho como este cursito y ahora te toca a ti.
Todo lo que he dejado, como lo he dejado, todo lo que has aprendido, cosas que no has entendido. Tócalas, rompelas, entiéndelas, cabréate, peleate y es así, ¿no?
Como lo tienes que ir haciendo. Y añadir nuevas funcionalidades, que yo creo que es súper interesante el hecho de decir, vale, pues lo he dejado hasta aquí, yo he visto el vídeo, pues ahora yo me voy a enfrentar.
Que muchas veces me decís, ostras, ¿cómo salgo del tutorial gel? Pues este es el momento en el que ahora has visto el tutorial, pero ahora tu momento es el hecho de cómo lo llevas al siguiente nivel.
Que creo que está súper, súper bien, ¿eh? ¿Está bien cabrearme el 99% del tiempo? Pues no, la verdad, porque es perder el tiempo. No vale la pena cabrearse todo el día, sinceramente.
No te lo recomiendo, no te lo recomiendo.