<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Julieta Campos Guzmán</title>
    <description>The latest articles on DEV Community by Julieta Campos Guzmán (@juliescript).</description>
    <link>https://dev.to/juliescript</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F203948%2Fb151b9cf-3c7c-4819-8cfe-c2b9e8c92542.jpg</url>
      <title>DEV Community: Julieta Campos Guzmán</title>
      <link>https://dev.to/juliescript</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/juliescript"/>
    <language>en</language>
    <item>
      <title>Usar LinkedIn para conseguir trabajo en el extranjero</title>
      <dc:creator>Julieta Campos Guzmán</dc:creator>
      <pubDate>Thu, 17 Mar 2022 10:04:35 +0000</pubDate>
      <link>https://dev.to/juliescript/usar-linkedin-para-conseguir-trabajo-en-el-extranjero-508g</link>
      <guid>https://dev.to/juliescript/usar-linkedin-para-conseguir-trabajo-en-el-extranjero-508g</guid>
      <description>&lt;p&gt;&lt;em&gt;De nuevo con mi disclaimer pero es importante que sepan que esto que les cuento es sólo mi experiencia. Así me pasó y así lo viví hace más de 5 años. Las cosas han cambiado mucho desde entonces pero sigue gente migrando y siguen habiendo vacantes. Espero que mi experiencia les pueda servir de algo.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;Lo primero que les quiero decir son las circunstancias con las que empecé a hacer esto porque eso es muy importante para mi caso.&lt;/p&gt;

&lt;p&gt;En mayo del 2016 empecé a trabajar como Frontend Dev usando Javascript. Antes de esto trabajé en muchos lados y como freelance usando PHP y WordPress. Sí sabía un poco de frontend pero no me había metido a fondo a la guerra de frameworks ni nada. Nunca usé AngularJS, ni Grunt, ni Gulp, ni nada. Mi primer experiencia con Javascript fue Angular RC 4. A los 4 meses de haber usado Angular por primera vez fue cuando decidí buscar trabajo en Alemania.&lt;/p&gt;

&lt;p&gt;Les digo esto porque en mi momento, el mercado estaba buscando devs con experiencia en Angular y tener esos pocos meses de experiencia ya me ponía en ventaja. Además en 2016 estaban contratando muchísimo.&lt;/p&gt;

&lt;p&gt;Ya que decidí aplicar a trabajos en Alemania hice lo siguiente:&lt;/p&gt;

&lt;h2&gt;
  
  
  Poner mi CV en inglés y mi LinkedIn en inglés y español
&lt;/h2&gt;

&lt;p&gt;Se dice que hay un formato especial de CV para Alemania. Yo nunca lo he usado pero si vas a aplicar a una empresa alemana tradicional, entonces vale la pena que lo busques. En mi caso estaba aplicando a startups, así que un CV normal en inglés me funcionó.&lt;/p&gt;

&lt;p&gt;Lo que incluí en el CV fue:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Datos personales: nombre, ubicación general, teléfono, email&lt;/li&gt;
&lt;li&gt;Experiencia laboral con resumen de mis actividades y lista de las tecnologías utilizadas&lt;/li&gt;
&lt;li&gt;Estudios&lt;/li&gt;
&lt;li&gt;Lista de idiomas que hablo&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;En LinkedIn lo hice un poco distinto ya que decidí hacerlo un poco distinto. En mi experiencia laboral puse un aprendizaje clave que obtuve de cada uno de mis trabajos. Fue un reto porque hay un límite de caracteres y yo quería ponerlo tanto en inglés como en español. ¿Por qué? Porque puedo.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cosas a considerar al escribir en inglés
&lt;/h2&gt;

&lt;p&gt;Afortunadamente, yo estudié inglés toda mi vida escolar así que no necesité ayuda para escribir mi CV en inglés. Sin embargo, nunca queda de más pedirle a alguien que le eche un ojo para asegurar que los mensajes que quieres transmitir sean claros.&lt;/p&gt;

&lt;p&gt;Si vas a aplicar a algún lugar en Europa, te recomiendo que uses &lt;a href="https://hemingwayapp.com"&gt;Hemingway App&lt;/a&gt; para checar el nivel de dificultad de tu texto. Muchas veces hacemos estructuras gramaticales muy complejas cuando escribimos en otro idioma porque queremos decir las cosas como en nuestro idioma nativo. No te olvides que tu audiencia no es necesariamente nativa en inglés y muchas veces tampoco tienen un nivel súper fluído para entender mensajes entre líneas.&lt;/p&gt;

&lt;p&gt;Es mucho mejor escribir las cosas de manera clara y en enunciados cortos. Esto facilita que tu lector no se pierda y da menos espacio a confusiones.&lt;/p&gt;

&lt;h2&gt;
  
  
  Buscar vacantes en la ciudad que quería
&lt;/h2&gt;

&lt;p&gt;En mi caso yo quería venir a Berlín así que enfoqué mi búsqueda a Alemania y a Berlín en especial. Apliqué usando el botón de &lt;code&gt;Apply through LinkedIn&lt;/code&gt; en todas las vacantes que me encontré que dijeran Angular 2 y visa sponsorship o relocation.&lt;/p&gt;

&lt;p&gt;Creo que ese es uno de mis puntos más importantes: aplica sólo a vacantes que explícitamente dicen que patrocinan visa o dan apoyo para mudarse. Ya me ha pasado que entro a entrevista a una empresa y al final me dicen que no gracias porque no dan patrocinio para visa.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mandar solicitudes
&lt;/h2&gt;

&lt;p&gt;Fácil mandé 50 solicitudes en LinkedIn. Lo demás fue esperar respuesta. Las cosas en Alemania usualmente no son súper rápidas, así que se tardan unas semanas en responder.&lt;/p&gt;

&lt;p&gt;Al final 4 empresas me contactaron para entrevista:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;una por recomendación de mi pareja - no quedé porque usaban AngularJS y yo no sabía AngularJS&lt;/li&gt;
&lt;li&gt;una por un servicio de reclutamiento que se llama Honeypot.io - me dieron oferta pero estaban en Hamburgo&lt;/li&gt;
&lt;li&gt;dos por LinkedIn - en una no quedé por la tarea de código y la otra es la empresa donde laboré cuando me mudé a Alemania&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Proceso de entrevista
&lt;/h2&gt;

&lt;p&gt;No voy a elaborar mucho sobre el proceso en sí porque es muy similar a lo que se vive actualmente en todos lados. Eso sí, todas las entrevistas se hacen en horario de Alemania, lo que significa que las tomaba a las 6am hora de México.&lt;/p&gt;

&lt;p&gt;Las entrevistas fueron todas en inglés. Pero no te preocupes, que de todas las entrevistas que hice sólo hablé con una persona que tenía inglés nativo. Todas las demás personas lo tenían como segundo o tercer idioma. Todos tenían acento, todos cometían errores y a nadie le importó. Lo más importante es que hables alto y claro.&lt;/p&gt;

&lt;p&gt;Algunas entrevistas fueron primero con reclutador, algunas empezaron luego luego con el Engineering Manager. Tuve sólo una que fue un live coding, pero me dejaron "sola" y me dijeron que implementara un cierto feature de un ejercicio en una hora. Las demás fueron con proyecto para hacer en casa.&lt;/p&gt;

&lt;p&gt;Después de la entrega del proyecto hubo otra entrevista técnica ya sea con el Lead o con futuros compañeros de trabajo. Aquí me preguntaron sobre mis proyectos, cosas que podría hacer mejor y preguntas para conocerme. Algo muy importante que me preguntaron muchas veces fue mi motivación para irme de mi país.&lt;/p&gt;

&lt;p&gt;Finalmente, me extendieron dos ofertas pero me fui por la de la empresa que estaba en Berlín. Tuve una última junta para checar el salario y mi fecha de entrada. Que ojo, no le vayan a hacer como yo y pidan el mínimo para la visa como salario. Se les debe de pagar justo. Tampoco se aceleren con querer empezar luego luego, las empresas alemanas están acostumbradas a esperar candidatos ya que aquí cuando renuncias tienes que cubrir 3 meses de cancelación de tu contrato. Sí, se te hace eterno.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Qué pasa después?
&lt;/h2&gt;

&lt;p&gt;Te mandan tu contrato por Fedex y &lt;a href="https://dev.to/juliescript/como-fue-mi-proceso-de-visa-para-alemania-46e1"&gt;vas a la embajada a sacar tu visa&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  En resumen
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Tener experiencia relevante y que esté en demanda en el mercado es súper importante&lt;/li&gt;
&lt;li&gt;Escribe tu CV y perfil de LinkedIn en inglés, si necesitas ayuda pide a alguien que te ayude a editar tus textos&lt;/li&gt;
&lt;li&gt;Aplica a todas las vacantes posibles&lt;/li&gt;
&lt;li&gt;Ten paciencia que acá las cosas son lentas&lt;/li&gt;
&lt;li&gt;En las entrevistas que no te de pena hablar inglés, es muy probable que quien te entrevista no es hablante nativo y nadie está ahí para calificar tu inglés&lt;/li&gt;
&lt;li&gt;No te apures por no poderte subir a un avión a la mañana siguiente de recibir tu contrato, es normal esperar a los candidatos en especial si vienen del extranjero&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Esto fue lo que me funcionó a mí hace 5 años. Actualmente sigo usando LinkedIn para buscar trabajo. Así conseguí mi trabajo actual que es mi segundo trabajo en Alemania.&lt;/p&gt;

&lt;p&gt;Me pueden dejar comentarios y dudas en &lt;a href="https://twitter.com/juliescriptdev"&gt;Twitter&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>trabajoenelextranjer</category>
      <category>alemania</category>
    </item>
    <item>
      <title>¿Cómo fue mi proceso de visa para Alemania?</title>
      <dc:creator>Julieta Campos Guzmán</dc:creator>
      <pubDate>Sun, 23 Jan 2022 15:26:35 +0000</pubDate>
      <link>https://dev.to/juliescript/como-fue-mi-proceso-de-visa-para-alemania-46e1</link>
      <guid>https://dev.to/juliescript/como-fue-mi-proceso-de-visa-para-alemania-46e1</guid>
      <description>&lt;p&gt;Antes de empezar a soltarles la sopa tengo algunas cosas que aclarar. Digamos que va a ser mi disclaimer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Trabajo como desarrolladora/ingeniero en software&lt;/li&gt;
&lt;li&gt;Tengo título universitario&lt;/li&gt;
&lt;li&gt;Tuve mucha gente que me ayudó a que todo saliera de forma relativamente sencilla&lt;/li&gt;
&lt;li&gt;Esto lo hice hace cinco años&lt;/li&gt;
&lt;li&gt;Lo que escribo aquí es todo lo que sé, es mi experiencia pero no será ni relativamente parecida a la de alguien más&lt;/li&gt;
&lt;li&gt;Les voy a poner links a la embajada de Alemania en México porque yo soy mexicana y ahí hice mi trámite&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ya con el disclaimer ahí podemos empezar.&lt;/p&gt;

&lt;p&gt;En Octubre de 2016 conseguí eso que tanto quería: un trabajo en Alemania. Era algo que se me hacía imposible pero logré convencer a una empresa de que me contratara y una vez que acepté la oferta empezó todo el show para la visa.&lt;/p&gt;

&lt;p&gt;La empresa que me contrató arregló una agencia de relocalización para ayudarme con el trámite, esto hizo todo mucho más sencillo. Sin embargo, desde que empecé a buscar trabajo ya tenía algunos papeles listos.&lt;/p&gt;

&lt;p&gt;La visa a la que apliqué fue a EU Blaue Karte, EU Blue Card o Tarjeta Azul de la Unión Europea. Es una visa de trabajo para profesiones dónde hay escasez de trabajadores. Lo padre es que esa visa no está ligada al empleador, es tuya y te permite cambiar de trabajo si así lo deseas. Al ser una visa para trabajos altamente calificados, el requisito de idioma es nulo.&lt;/p&gt;

&lt;p&gt;Yo ya sabía que encontrar cita para la visa era un viacrucis. Así que desde que decidí buscar trabajo también agendé mi cita para la visa. Cualquier cosa la podía cancelar, así que me adelanté un poco e hice la cita sin tener ninguna propuesta de trabajo.&lt;/p&gt;

&lt;p&gt;Al mismo tiempo que hice la cita también me informé de &lt;a href="https://mexiko.diplo.de/blob/875284/83da38253cfa9dbc5f5dd49461234ce8/15-merkblattbluecard-download-data.pdf"&gt;los requisitos para la Blue Card&lt;/a&gt;, así que me puse a juntar los papeles necesarios.&lt;/p&gt;

&lt;p&gt;En mi caso necesité:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Contrato de trabajo con sueldo mayor a una cierta cantidad que no me acuerdo cual era en ese momento&lt;/li&gt;
&lt;li&gt;Seguro médico alemán&lt;/li&gt;
&lt;li&gt;Título universitario apostillado y traducido a alemán&lt;/li&gt;
&lt;li&gt;Comprobante de &lt;a href="https://anabin.kmk.org/anabin.html"&gt;ANABIN&lt;/a&gt; del título&lt;/li&gt;
&lt;li&gt;Pasaporte&lt;/li&gt;
&lt;li&gt;El formulario de solicitud&lt;/li&gt;
&lt;li&gt;Fotos biométricas&lt;/li&gt;
&lt;li&gt;Copias de todo&lt;/li&gt;
&lt;li&gt;Pago de la visa que en ese entonces fueron 160 euros&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cuando ya tuve el contrato, contacté a la embajada porque no encontraba mi título y quería ver qué tenía que hacer. Sin embargo, me contestaron que llevara un comprobante de los resultados que salían de la página y que no me preocupara. Así que no me preocupé e hice lo que me dijeron.&lt;/p&gt;

&lt;p&gt;Con la agencia de relocalización vi que la solicitud fuera correcta y compré &lt;a href="https://www.hansemerkur.de/versicherungen-fuer-auslaendische-gaeste/visum-plus-versicherung"&gt;un seguro médico que ellos me recomendaron&lt;/a&gt; por tres meses.&lt;/p&gt;

&lt;p&gt;Llegó Noviembre y con él mi cita para la visa. Revisé mis documentos ocho veces y mi mamá me acompañó a la embajada. Ojo, no se puede entrar con nada a la embajada no bolsas, no celulares, nada de nada, sólo tu persona y tus documentos.&lt;/p&gt;

&lt;p&gt;Ya en la embajada pasé con la cónsul y cuándo vio que el comprobante del título y el título no coincidían me preguntó porque lo llevé así. Ya le conté que había escrito a la embajada y había recibido respuesta de llevarlo así. La cónsul me preguntó el nombre de quién me respondió eso y cuándo le dijo ella me comentó que esa persona procesa las visas, así que si había dicho que estaba bien entonces no iba a haber problema.&lt;/p&gt;

&lt;p&gt;Pagué por el trámite, recogí mis documentos y me fui de compras con mi mamá.&lt;/p&gt;

&lt;p&gt;A las tres horas recibí un correo de la embajada donde decía que mi visa estaba lista y podía pasar por ella al siguiente lunes.&lt;/p&gt;

&lt;p&gt;Y esa es la historia de como saqué mi visa.&lt;/p&gt;

&lt;p&gt;Todo parece muy sencillo porque tuve muchísima ayuda y muchísima suerte. Como les dije al principio mi proceso y el de otra persona van a ser muy distintos. Hay muchísimos factores a considerar y lo que me pasó a mí puede que no le pasé a alguien más.&lt;/p&gt;

&lt;p&gt;Ahora les contesto otras dudas que me han llegado por DM:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;¿Homologáste tu título?&lt;/strong&gt;
No, yo no hice ese proceso porque me dijeron que no era necesario. Sin embargo, recomiendo que escribas personalmente a la embajada y preguntes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;¿Te han pedido título para buscar o solicitar trabajo?&lt;/strong&gt;
Para buscar o solicitar trabajo no. Trabajo como desarrolladora de software, así que los títulos no importan en mi industria. La empresa para la que actualmente trabajo me pidió el título una vez que me contrató y sólo fue para comprobar mis estudios, no tenía que ser un título universitario ni me pidieron apostilla ni nada.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;¿Sabías alemán o necesitas alemán para buscar trabajo?&lt;/strong&gt;
De nuevo, en mi industria la mayoría de las posiciones que se encuentran son en inglés porque la mayoría de los desarrolladores son extranjeros. Así que yo no sabía alemán antes de irme. Puedes aprender alemán desde antes, siempre ayuda a los trámites ya que llegas, pero no es necesario. Lo que sí necesitas es que no te de pena hablar y escribir en inglés.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Hasta aquí el post de hoy, díganme en Twitter si tienen otras dudas. También les puedo escribir sobre cómo conseguí mi trabajo o shocks culturales que tuve llegando a Alemania. :)&lt;/p&gt;

</description>
      <category>alemania</category>
      <category>visa</category>
      <category>spanish</category>
    </item>
    <item>
      <title>¿Cómo hacer un blog usando Gatsby y Ghost? - Parte 1</title>
      <dc:creator>Julieta Campos Guzmán</dc:creator>
      <pubDate>Tue, 21 Jul 2020 18:53:49 +0000</pubDate>
      <link>https://dev.to/juliescript/como-hacer-un-blog-usando-gatsby-y-ghost-parte-1-130c</link>
      <guid>https://dev.to/juliescript/como-hacer-un-blog-usando-gatsby-y-ghost-parte-1-130c</guid>
      <description>&lt;h3&gt;
  
  
  Mi breve historia con los blogs
&lt;/h3&gt;

&lt;p&gt;Desde hace muchísimos años, estoy hablando del 2003/2004 encontré plataformas como LiveJournal o Blogger y empecé a ver que mucha gente escribía diarios en línea. Algo así como lo que eran las páginas de GeoCities en los 90's que tenían páginas de visitas y eran lugares divertidos para escribir cualquier cosa.&lt;/p&gt;

&lt;p&gt;Desde ese entonces me ha interesado muchísimo este fenómeno de tener un sitio web propio y llenarlo de contenido y con el pasar de los años he intentado crear y mantener un blog.&lt;/p&gt;

&lt;p&gt;Es más, en el 2007 aprendí a usar WordPress y de ahí me volví soporte técnico de blogging para varias chicas que tenían blogs de moda. Me pagaban para ayudarles a modificar sus comentarios, los menús, hasta conseguí trabajos con influencers grandes de esa época. Me especialicé tanto en WordPress que trabajé desarrollando sitios en WordPress hasta inicios de 2016.&lt;/p&gt;

&lt;p&gt;Durante todo eso, siempre tuve un sitio como proyecto para probar las cosas nuevas que salían pero nunca logré tener una audiencia o desarrollar un presencia en línea. Nunca hice mucho sobre monetización ni nada por el estilo.&lt;/p&gt;

&lt;p&gt;Ahora estoy escribiendo este blog para generar un recurso para la yo del pasado y todas esas personas que pasan por estos pequeños problemas y no encuentran las soluciones fácilmente.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Por qué Gatsby?
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://www.gatsbyjs.org/"&gt;GatsbyJS&lt;/a&gt; me llamó la atención porque no conocía los generadores de sitios estáticos. Todo mundo decía que era muy sencillo de usar, incluso yo cuando creé este sitio, pero luego me di cuenta que para hacer cosas más complejas realmente hay que conocer todas sus partes. Hay que saber usar &lt;a href="https://reactjs.org"&gt;React&lt;/a&gt;, hay que saber usar &lt;a href="https://graphql.org/"&gt;GraphQL&lt;/a&gt; y hay que saber configurar Gatsby para lograr lo que quieres. Hacer la instalación inicial es muy rápido con su &lt;a href="https://www.gatsbyjs.org/docs/quick-start#use-the-gatsby-cli"&gt;herramienta de línea de comando (CLI)&lt;/a&gt;, pero después se puede volver confuso para cambiar cosas.&lt;/p&gt;

&lt;p&gt;Quiero seguir intentando con Gatsby porque me ha gustado la experiencia de usar GraphQL pero aún tengo mucho que aprender en términos de cómo Gatsby funciona internamente y otras cosas que puedo hacer con él.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Por qué Ghost?
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://ghost.org/"&gt;Ghost&lt;/a&gt; es un administrador de contenido hecho en Node. Recuerdo la primera vez que escuché de él fue por ahí del 2013. No lo usé al principio porque recuerdo que mi compañía de hosting no lo soportaba. Después lo usé brevemente en 2017 cuando recién me mudé a Alemania pero la verdad es que el diseño y las plantillas no me gustaban y no quise aprender a hacer temas en &lt;a href="https://handlebarsjs.com/"&gt;Handlebars&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Después de que leí un &lt;a href="https://www.smashingmagazine.com/2020/01/migration-from-wordpress-to-jamstack/"&gt;artículo en Smashing Magazine sobre usar CMS en modo headless&lt;/a&gt;, o sea como fuentes de contenido en lugar de tener el contenido y el front-end en el mismo lugar decidí buscar si eso se podía hacer con Ghost. Pues &lt;a href="https://gatsby.ghost.org/"&gt;resulta que sí se puede&lt;/a&gt; y tienen tanto un &lt;a href="https://github.com/TryGhost/gatsby-source-ghost"&gt;plugin de Gatsby para hacerlo&lt;/a&gt;, como un &lt;a href="https://github.com/tryghost/gatsby-starter-ghost"&gt;proyecto listo para empezar a usar Ghost&lt;/a&gt;. Además &lt;a href="https://ghost.org/integrations/netlify/"&gt;se puede usar junto con Netlify&lt;/a&gt; y todos los aspectos de administrar y publicar tu sitio están cubiertos.&lt;/p&gt;

&lt;h3&gt;
  
  
  Ahora sí, vamos a empezar
&lt;/h3&gt;

&lt;p&gt;Para crear un blog con Gatsby y Ghost se necesitan dos cosas:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Una instalación de Ghost&lt;/li&gt;
&lt;li&gt;Un proyecto de Gatsby&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;em&gt;Nota: todo este tutorial se puede hacer en localhost, pero para ponerlo en línea usé un droplet de Digital Ocean para poner mi instalación de Ghost y alimentar el front-end en Gatsby.&lt;/em&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Paso 1: Instalar Gatsby
&lt;/h4&gt;

&lt;p&gt;Para instalar Gatsby hay que instalar su herramienta de línea de comando. Como lo mencioné en mi post anterior sobre crear blogs con Gatsby, hay que correr el siguiente comando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm i -g gatsby-cli

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Paso 2: Instalar Ghost
&lt;/h4&gt;

&lt;p&gt;Para instalar la herramienta de Ghost en un ambiente local, hay que correr el comando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo npm install -g ghost-cli

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Esto nos permitirá crear el blog en Ghost que servirá para alimentar de contenido nuestro front-end en Gatsby.&lt;/p&gt;

&lt;h4&gt;
  
  
  Paso 3: Crear un blog en Ghost
&lt;/h4&gt;

&lt;p&gt;Primero vamos a crear el blog en Ghost. Esto es importante ya que necesitaremos algunos datos de la instalación de Ghost para conectarla con Gatsby.&lt;/p&gt;

&lt;p&gt;Crea un nuevo directorio para tu blog en Ghost:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mkdir ghost-blog &amp;amp;&amp;amp; cd ghost-blog
ghost install local

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sigue las instrucciones de instalación y crea tu usuario de Ghost.&lt;/p&gt;

&lt;p&gt;Cabe mencionar que la instancia de Ghost se quedará funcionando en segundo plano, así que no necesitas correrla activamente para usarlo.&lt;/p&gt;

&lt;p&gt;Una vez dentro, en el menú elige &lt;code&gt;Integrations&lt;/code&gt; y vas a ver una opción que se llama &lt;code&gt;+ Add custom integration&lt;/code&gt;. Se va a ver algo así:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ZLyrZoCD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://api.juliescript.dev/content/images/2020/08/Screenshot-2020-08-03-at-23.00.58.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZLyrZoCD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://api.juliescript.dev/content/images/2020/08/Screenshot-2020-08-03-at-23.00.58.png" alt="" width="880" height="184"&gt;&lt;/a&gt;Vista de integraciones en la sección administrativa de Ghost&lt;/p&gt;

&lt;p&gt;Oprime &lt;code&gt;+ Add custom integration&lt;/code&gt; y dale un nombre a tu instalación. Yo la llamé &lt;code&gt;Gatsby&lt;/code&gt; para mantener las cosas sencillas.&lt;/p&gt;

&lt;p&gt;Ya que creaste la integración, vas a ver una pantalla con algunos datos, entre ellos uno llamado &lt;code&gt;Content API Key&lt;/code&gt;. Esta llave es la que necesitamos para poder alimentar el contenido a Gatsby. Así que mantenla a la mano para lo que sigue.&lt;/p&gt;

&lt;h4&gt;
  
  
  Paso 4: Crear un sitio de Gatsby
&lt;/h4&gt;

&lt;p&gt;Para crear un sitio en Gatsby usando la herramienta de línea de comando, vamos a correr el siguiente comando en la consola:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;gatsby new gatsby-site https://github.com/gatsbyjs/gatsby-starter-hello-world

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Este comando va a llamar el repositorio de la plantilla de inicio para hacer un sitio en Gatsby. Este sitio va a tener las cosas básicas que necesitamos para empezar a trabajar, es el equivalente a escribir "Hola Mundo" usando Gatsby.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;La razón por la que no elegí usar la plantilla que ya trae Gatsby conectado a Ghost o usar la plantilla de blog de Gatsby es que estas plantillas traen muchas configuraciones. Todas esas configuraciones añaden una capa de complejidad a la hora de querer cambiar estilos o hacer cosas distintas a las predeterminadas. Me gusta mucho más tomar lo básico y aprender desde lo más abajo posible para después poder entender cómo funcionan las configuraciones más complejas. Por eso hoy empezaremos a trabajar con la plantilla inicial y no con algo más elaborado.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Ya que terminó el instalador, vamos a cambiar de carpeta y a correr nuestro servidor de Gatsby en modo de desarrollo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd gatsby-site
gastby develop

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Si todo salió bien, debes de ver poder visitar &lt;code&gt;http://localhost:8000&lt;/code&gt; y ver las palabras &lt;code&gt;Hello World&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--WTPekDMR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://api.juliescript.dev/content/images/2020/08/Screenshot-2020-08-04-at-21.04.40.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--WTPekDMR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://api.juliescript.dev/content/images/2020/08/Screenshot-2020-08-04-at-21.04.40.png" alt="" width="384" height="177"&gt;&lt;/a&gt;Muestra de como se ve "Hello World!" en la plantilla básica de Gatsby&lt;/p&gt;

&lt;p&gt;Si te fijas en la consola, vas a ver que existe otra dirección, &lt;code&gt;http://localhost:8000/___graphql&lt;/code&gt;, si vamos a esta URL podemos ver una instancia de &lt;a href="https://github.com/graphql/graphiql"&gt;GraphiQL&lt;/a&gt;. En esta parte podemos probar las diferentes consultas y operaciones que se pueden hacer con GraphQL y Gatsby antes de ponerlas en el código.&lt;/p&gt;

&lt;p&gt;Vamos a jugar bastante con esta consola más adelante para crear las consultas que usaremos en el blog.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--uA_x8SPh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://api.juliescript.dev/content/images/2020/08/Screenshot-2020-08-04-at-21.10.33.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--uA_x8SPh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://api.juliescript.dev/content/images/2020/08/Screenshot-2020-08-04-at-21.10.33.png" alt="" width="880" height="333"&gt;&lt;/a&gt;Vista de GraphiQL en un proyecto nuevo de Gatsby&lt;/p&gt;

&lt;h4&gt;
  
  
  Paso 5: Conectar Gatsby y Ghost
&lt;/h4&gt;

&lt;p&gt;Algo bien padre que hizo la comunidad de Ghost fue crear un plugin para Gastby que crea la conexión entre la API de Ghost y el GraphQL de Gatsby. Usar un sistema de blog de esta forma se llama &lt;code&gt;headless CMS&lt;/code&gt; o administrador de contenido sin cabeza.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Headless CMS&lt;/code&gt; se refiere a que en lugar de usar el CMS para guardar el contenido y presentarlo, usamos sólo los datos y los presentamos en otro lado. En este caso, usaremos Gatsby para hacer un sitio estático usando los datos de Ghost.&lt;/p&gt;

&lt;p&gt;El plugin se llama &lt;a href="https://github.com/TryGhost/gatsby-source-ghost"&gt;&lt;code&gt;gatsby-source-ghost&lt;/code&gt;&lt;/a&gt; y lo vamos a agregar a Gatsby de la siguiente manera:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn add gatsby-source-ghost

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ya que está instalado, hay que abrir el archivo &lt;code&gt;gatsby-config.js&lt;/code&gt;. Este archivo va a tener todas las configuraciones que necesitamos para hacer funcionar el sitio. Para configurar nuestro Ghost hay que añadir el siguiente bloque de código dentro de &lt;code&gt;plugins: []&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
   resolve: `gatsby-source-ghost`,
   options: {
       apiUrl: `https://&amp;lt;your-subdomain&amp;gt;.ghost.io`,
       contentApiKey: `&amp;lt;your content api key&amp;gt;`,
       version: `v3` // Ghost API version, optional, defaults to "v3".
                     // Pass in "v2" if your Ghost install is not on 3.0 yet!!!
   }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;apiUrl&lt;/code&gt; - aquí va la URL de la instalación de Ghost, si es local entonces hay que poner la URL del localhost.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;contentApiKey&lt;/code&gt; - la llave que sacamos cuando hicimos la integración en Ghost&lt;/li&gt;
&lt;li&gt;version: la versión de Ghost&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ahora hay que reiniciar el servidor de Gatsby para ver los cambios.&lt;/p&gt;

&lt;p&gt;En la parte visual no se va a notar nada ya que no hemos cambiado la interfaz. Entonces hay que visitar GraphiQL para ver las nuevas interfaces que tenemos disponibles.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--EKihTKry--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://api.juliescript.dev/content/images/2020/08/Screenshot-2020-08-04-at-21.36.23.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--EKihTKry--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://api.juliescript.dev/content/images/2020/08/Screenshot-2020-08-04-at-21.36.23.png" alt="" width="880" height="401"&gt;&lt;/a&gt;Actualización de GraphiQL después de instalar el plugin de Ghost&lt;/p&gt;

&lt;p&gt;Ahora nuestro Ghost está conectado con Gatsby. Es importante notar que cada que hagamos un cambio en Ghost, será necesario volver a compilar el sitio en Gatsby.&lt;/p&gt;

&lt;p&gt;Ahora podemos hacer consultas a nuestro sistema en Ghost. Una de ejemplo puede ser para conseguir datos del sitio, como el título y la descripción.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;query MyQuery {
  ghostSettings {
    title
    description
  }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;En el caso de mi sitio el resultado va a ser:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "data": {
    "ghostSettings": {
      "title": "Juliescript",
      "description": "Otro blog de tecnología en español."
    }
  },
  "extensions": {}
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;¡Al fin tenemos Gatsby y Ghost conectados!&lt;/p&gt;




&lt;p&gt;Con esto se termina el tutorial de hoy pero en la siguiente parte veremos como crear páginas usando las consultas de Ghost.&lt;/p&gt;

</description>
      <category>gatsby</category>
      <category>ghost</category>
      <category>spanish</category>
      <category>blogging</category>
    </item>
    <item>
      <title>Así trabajo desde casa - mi escritorio y rutina</title>
      <dc:creator>Julieta Campos Guzmán</dc:creator>
      <pubDate>Mon, 27 Apr 2020 13:42:00 +0000</pubDate>
      <link>https://dev.to/juliescript/asi-trabajo-desde-casa-mi-escritorio-y-rutina-2194</link>
      <guid>https://dev.to/juliescript/asi-trabajo-desde-casa-mi-escritorio-y-rutina-2194</guid>
      <description>&lt;p&gt;&lt;em&gt;Quiero empezar este post reconociendo el gran privilegio de tener un trabajo estable, de tiempo completo, que me permite trabajar desde mi casa. No todos lo tenemos y reconozco el valor que tienen aquellos que salen todos los días para mantener a su familia durante esta situación.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;Desde que nos mudamos al departamento donde vivimos actualmente, quisimos tener un espacio dedicado para el trabajo. Mi prometido y yo somos ingenieros en software y ocasionalmente trabajamos desde casa. También tenemos varios hobbies que involucran usar la computadora, así que tener unos buenos escritorios y unas sillas apropidas para trabajar era prioridad para nosotros.&lt;/p&gt;

&lt;p&gt;Con el tiempo hemos agregado cosas para hacer nuestro espacio de trabajo más cómodo. Ahora que llevamos más de un mes trabajando desde casa, la inversión en nuestro espacio de trabajo ha valido muchísimo la pena. Podemos trabajar cómodamente, separar nuestro trabajo del resto de la casa y mantenernos concentrados durante el día.&lt;/p&gt;

&lt;p&gt;Mi escritorio en particular se ve así:&lt;/p&gt;

&lt;p&gt;&lt;a href="///static/635492a20afcfa75e6745d9541877e08/c2b56/20200426_170751.jpg"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ql-SbQzB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://juliescript.dev/static/635492a20afcfa75e6745d9541877e08/c739e/20200426_170751.jpg" alt="Escritorio vista completa" title="Escritorio vista completa"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="///static/aaec3a0e366add25f8cf1cb9b750294d/243ce/20200426_171515.jpg"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--tddyf1qu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://juliescript.dev/static/aaec3a0e366add25f8cf1cb9b750294d/c739e/20200426_171515.jpg" alt="Escritorio vista desde arriba" title="Escritorio vista desde arriba"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Escritorio - &lt;a href="https://www.ikea.com/de/de/p/lillasen-schreibtisch-bambus-90278277/"&gt;Lillåsen&lt;/a&gt; de IKEA&lt;/li&gt;
&lt;li&gt;Silla - &lt;a href="https://www.ikea.com/de/de/p/langfjaell-konferenzstuhl-gunnared-beige-schwarz-s59174965/"&gt;Långfjäll&lt;/a&gt; de IKEA&lt;/li&gt;
&lt;li&gt;Descansa Pies - &lt;a href="https://www.ikea.com/de/de/p/dagotto-fussstuetze-schwarz-40240989/"&gt;Dagotto&lt;/a&gt; de IKEA&lt;/li&gt;
&lt;li&gt;Lámpara - &lt;a href="https://www.ikea.com/de/de/p/forsa-arbeitsleuchte-weiss-30439117/"&gt;Forså&lt;/a&gt; de IKEA, la que tengo en mi escritorio no la encontré en el sitio pero esta es la de mi prometido&lt;/li&gt;
&lt;li&gt;Stand para celular/tablet - &lt;a href="https://www.ikea.com/de/de/p/sigfinn-mobiltelefonhalter-bambusfurnier-30383059/"&gt;Sigfinn&lt;/a&gt; de IKEA&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sí, somos totalmente IKEA.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Stand para laptop: &lt;a href="https://www.amazon.de/-/en/gp/product/B01F01DRW6/"&gt;mStand&lt;/a&gt; de Rain Design&lt;/li&gt;
&lt;li&gt;Hub para cargar dispositivos USB de &lt;a href="https://www.amazon.de/-/en/gp/product/B01HZF7CJO/"&gt;Aukey&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Monitor &lt;a href="https://www.amazon.de/-/en/gp/product/B07JDGSPFM/"&gt;Dell U2419H&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Teclado &lt;a href="https://www.logitech.com/de-de/product/k860-split-ergonomic-keyboard?crid=27"&gt;Logitech Ergo K860&lt;/a&gt;, este lo compré con descuento de mi empresa&lt;/li&gt;
&lt;li&gt;Audífonos &lt;a href="https://www.amazon.de/-/en/WH-1000XM3-Bluetooth-Canceling-headphones-Headphones/dp/B07GDR2LYK/"&gt;Sony WH-1000XM3&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;Apple Magic Trackpad 2&lt;/li&gt;
&lt;li&gt;Macbook Pro 15 pulgadas, es la del trabajo&lt;/li&gt;
&lt;li&gt;Macbook Air 13 pulgadas, es la personal&lt;/li&gt;
&lt;li&gt;Y muchos, muchos cables&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="///static/7b713c862796b7c1f5fc56d31db71387/c2b56/20200426_171446.jpg"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9uCyGiyv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://juliescript.dev/static/7b713c862796b7c1f5fc56d31db71387/c739e/20200426_171446.jpg" alt="Escritorio vista cerca" title="Escritorio vista cerca"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="///static/23f9fb734e6aae37180ea3cf7696d7d7/243ce/20200426_170900.jpg"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--dMLW7U8F--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://juliescript.dev/static/23f9fb734e6aae37180ea3cf7696d7d7/c739e/20200426_170900.jpg" alt="Escritorio close up Calcifer" title="Escritorio close up Calcifer"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="///static/b8596832e0674a41fbefa47f1bd9b155/243ce/20200426_170840.jpg"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Ro3rTCz---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://juliescript.dev/static/b8596832e0674a41fbefa47f1bd9b155/c739e/20200426_170840.jpg" alt="Escritorio teclado y compu" title="Escritorio teclado y compu"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="///static/581df653269c7d4225caf4dde3b8510d/c2b56/20200426_171549.jpg"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9DvanxkH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://juliescript.dev/static/581df653269c7d4225caf4dde3b8510d/c739e/20200426_171549.jpg" alt="Escritorio vista completa" title="Escritorio vista completa"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;La rutina que medio me he hecho ha sido la siguiente:&lt;/p&gt;

&lt;p&gt;Despierto cerca de las 8:00, me baño y arreglo para trabajar. Normalmente me maquillo para trabajar porque me gusta estar arreglada, pero no es algo que haga diario o a fuerza. Normalmente desayunamos un cereal en frente de la compu y empieza el día de trabajo.&lt;/p&gt;

&lt;p&gt;Mi primer junta del día siempre es mi stand up a las 9:45, así que antes de eso debo de estar conectada y revisando mis tareas del día. Dependiendo del día, a veces tengo juntas o a veces no tengo nada agendado. Sin embargo, tengo varias video llamadas al día para platicar con mis compañeros sobre el proyecto en el que estamos trabajando.&lt;/p&gt;

&lt;p&gt;A las 11:45 sale mi recordatorio de la comida, así que por ahí de las 12 me levantó del escritorio y cocino. Si pedimos comida a domicilio, entonces pedimos antes de las 12 y esperamos a que llegue. Tratamos de comer juntos y en la cocina para tener un verdadero respiro del trabajo. Entre 45 minutos y 1 hora es lo que nos damos para comer y regresamos a trabajar.&lt;/p&gt;

&lt;p&gt;Durante el tiempo de trabajo me doy 2 descansos de 15 minutos para preparar té, descansar mis ojos y estirar un poco las piernas.&lt;/p&gt;

&lt;p&gt;El día de trabajo termina a las 17:00, a veces media hora más. Normalmente me pongo a ver YouTube o a jugar Animal Crossing. Algunas veces vamos a caminar después del trabajo o a hacer algo que tenga pendiente como sacar la basura o ir al super mercado.&lt;/p&gt;

&lt;p&gt;Estuve haciendo ejercicio constante durante unas 2 o 3 semanas pero no lo incluyo en la rutina porque no es algo que hago diario a cierto tiempo. Lo hago cuando tengo ganas y no siempre a la misma hora.&lt;/p&gt;

&lt;p&gt;Mi rutina diaria no difiere mucho de mi rutina normal sin pandemia. La única diferencia es que no tengo que tomarme tiempo para llegar a la oficina. Aún así extraño mucho a mis compañeros e ir a la oficina. Me gusta mucho socializar con mi equipo y aunque hablamos mucho, no es lo mismo.&lt;/p&gt;

&lt;p&gt;¿Ustedes cómo se han sentido con la pandemia?&lt;/p&gt;

</description>
      <category>español</category>
      <category>spanish</category>
      <category>wfh</category>
      <category>homeoffice</category>
    </item>
    <item>
      <title>Hicimos el sitio web de nuestra boda en Angular y Rust</title>
      <dc:creator>Julieta Campos Guzmán</dc:creator>
      <pubDate>Fri, 24 Apr 2020 13:42:00 +0000</pubDate>
      <link>https://dev.to/juliescript/hicimos-el-sitio-web-de-nuestra-boda-en-angular-y-rust-pk8</link>
      <guid>https://dev.to/juliescript/hicimos-el-sitio-web-de-nuestra-boda-en-angular-y-rust-pk8</guid>
      <description>&lt;h2&gt;
  
  
  La historia
&lt;/h2&gt;

&lt;p&gt;En agosto del año pasado nos comprometimos durante nuestras vacaciones en Japón.&lt;/p&gt;

&lt;p&gt;Decidimos planear nuestra boda en México porque aunque vivimos en Alemania, nuestras familias están en México y es donde queremos celebrar con todos nuestros seres queridos.&lt;/p&gt;

&lt;p&gt;Una de las partes más importantes de planear una boda son las invitaciones. Usualmente se hacen de forma física, son cosas muy hermosas y elaboradas que se envían a los invitados. En ellas se encuentran todos los datos sobre la boda como:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fecha&lt;/li&gt;
&lt;li&gt;Lugar&lt;/li&gt;
&lt;li&gt;Hora&lt;/li&gt;
&lt;li&gt;Programa&lt;/li&gt;
&lt;li&gt;Etiqueta&lt;/li&gt;
&lt;li&gt;Mesa de regalos&lt;/li&gt;
&lt;li&gt;Boletos para la recepción&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Hacer invitaciones no es una opción para nosotros. Tenemos que coordinar invitados que vienen de distintas ciudades y de distintos países. Además de que mandarlas a hacer puede ser muy caro y enviarlas es mucho trabajo.&lt;/p&gt;

&lt;p&gt;Por eso fue que decidimos usar nuestras habilidades como desarrolladores y unir fuerzas para crear un sitio web para nuestra boda.&lt;/p&gt;

&lt;h2&gt;
  
  
  El sitio
&lt;/h2&gt;

&lt;p&gt;Nuestro sitio va a tener dos funciones principales:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Dar la información sobre la boda&lt;/li&gt;
&lt;li&gt;Administrar la asistencia de los invitados&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Así que pensamos en crear un sistema que sirviera para que los invitados confirmen su asistencia y que después podamos enviar la invitación más formal en PDF antes del mero día de la boda.&lt;/p&gt;

&lt;p&gt;Para lograr esto nos dividimos el trabajo. Mi prometido se encargó de hacer todo el backend y yo me encargué de hacer el frontend. Entre los dos decidimos en un diseño y agregamos el contenido a la página. Mi prometido se encargó de traducir los textos porque necesitamos tener el sitio en español e inglés.&lt;/p&gt;

&lt;p&gt;Va sin recalcar que tenemos excepciones para invitados que no saben o que no tienen acceso a la web.&lt;/p&gt;

&lt;h3&gt;
  
  
  El tech stack
&lt;/h3&gt;

&lt;p&gt;Para el backend, todo fue manejaod por mi prometido así que no entraré en muchos detalles.&lt;/p&gt;

&lt;p&gt;El lenguaje de programación fue Rust porque es el lenguaje que está usando ahora.&lt;/p&gt;

&lt;p&gt;El stack del backend terminó así:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://github.com/ngx-translate/core"&gt;Rust&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://gotham.rs/"&gt;Gotham&lt;/a&gt; - para manejar el API&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://diesel.rs/"&gt;Diesel&lt;/a&gt; - para conectar y administrar la base de datos&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.postgresql.org/"&gt;PostgreSQL&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/features/actions"&gt;GitHub Actions&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Hosting en &lt;a href="https://www.digitalocean.com/"&gt;Digital Ocean&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;El stack del frontend fue el siguiente:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://angular.io/"&gt;Angular 9&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://sass-lang.com/"&gt;SASS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Deploy en &lt;a href="https://www.netlify.com/"&gt;Netlify&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Para el manejo de usuarios decidimos usar Facebook y Google login. La verdad no queríamos quedarnos con información personal del usuario y no quisimos lidiar con GDPR.&lt;/p&gt;

&lt;h3&gt;
  
  
  El proceso
&lt;/h3&gt;

&lt;p&gt;En el momento en que empezamos a planear el sitio, mi prometido estaba tomando una clase de administración de proyectos web para su maestría. Por mi lado, he tomado varios talleres de generación de ideas y de crear proyectos de forma ágil.&lt;/p&gt;

&lt;p&gt;De nuevo juntamos recursos e hicimos una sesión para definir que es lo que necesitaba la página y que es lo que queríamos lograr. Al final terminamos poniendo todas las tareas en un tablero tipo Kanban en JIRA. Esto nos ayudó mucho a mantener nuestro objetivo en la mira.&lt;/p&gt;

&lt;h3&gt;
  
  
  El diseño
&lt;/h3&gt;

&lt;p&gt;El diseño fue decisión principalmente mía. La verdad soy pésima diseñando así que me puse a buscar inspiración en Pinterest y otros sitios como Wix y Squarespace.&lt;/p&gt;

&lt;p&gt;Al final decidí reproducir una plantilla de sitio para boda de Squarespace. El diseño nos gustó mucho porque era sencillo y elegante. El esquema de colores es neutral y no se ve super feminino o masculino.&lt;/p&gt;

&lt;p&gt;Es un diseño bastante sobrio y la tipografía me encantó.&lt;/p&gt;

&lt;p&gt;Además de que ya viene con diseño móvil que siempre es un viacrucis incluir.&lt;/p&gt;

&lt;p&gt;&lt;a href="///static/c6c74b8d73d3f4a4c0414d4943d59327/8d0ff/squarespace-home.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fPwv5i2O--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://juliescript.dev/static/c6c74b8d73d3f4a4c0414d4943d59327/b9e4f/squarespace-home.png" alt="Plantilla Squarespace home" title="Plantilla Squarespace home" width="590" height="810"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="///static/d451c9fb517beddf075f4fd3827ba06f/8d0ff/squarespace-about.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7x_VbK3a--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://juliescript.dev/static/d451c9fb517beddf075f4fd3827ba06f/b9e4f/squarespace-about.png" alt="Plantilla Squarespace about" title="Plantilla Squarespace about" width="590" height="585"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Plantilla &lt;a href="https://morena-demo.squarespace.com/"&gt;Morena&lt;/a&gt; de Squarespace&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;A partir del diseño creamos las demás páginas que no estaban definidas.&lt;/p&gt;

&lt;p&gt;No tiene nada de malo reproducir un diseño ya creado si no eres bueno en diseño o si no puedes pagarle a un diseñador.&lt;/p&gt;

&lt;h3&gt;
  
  
  El frontend
&lt;/h3&gt;

&lt;p&gt;Jugué con la idea de hacer el frontend con React y Gatsby pero la verdad es que me siento mucho más cómoda con Angular. Puedo resolver problemas mejor y no tengo que sufrir tanto conectándome al backend.&lt;/p&gt;

&lt;p&gt;Además de que estilizar Angular es algo que es un sueño cuando lo haces con SASS. Es mi tech stack favorito y me ha servido bien varios años ya.&lt;/p&gt;

&lt;p&gt;El mapa del sitio quedó de la siguiente manera:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Página principal&lt;/li&gt;
&lt;li&gt;Información de la boda&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  - Información de viaje
&lt;/h2&gt;

&lt;p&gt;RSVP&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Login&lt;/li&gt;
&lt;li&gt;Redirección de login de facebook&lt;/li&gt;
&lt;li&gt;Página de perfil

&lt;ul&gt;
&lt;li&gt;404&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Diseño responsivo
&lt;/h4&gt;

&lt;p&gt;Hacer sitios responsivos creo que es algo que nos llega a dar mucha flojera a varios programadores. Hay muchas variables y hay que escribir mucho código. Afortunadamente pude usar casi puro CSS para manejar el diseño responsivo.&lt;/p&gt;

&lt;p&gt;La única ocasión donde tuve que incorporar Javascript fue con el menú para dispositivos móviles. Necesitaba manejar cuando activo y desactivo el menú y no me quise complicar la vida. Así que fue con Javascript.&lt;/p&gt;

&lt;h4&gt;
  
  
  Facebook y Google Login
&lt;/h4&gt;

&lt;p&gt;Para el manejo de usuario usamos Google y Facebook login. Toda la implementación la hizo mi prometido en Rust, así que del lado del frontend me tocó manejar las redirecciones.&lt;/p&gt;

&lt;p&gt;El flujo que tenemos es el siguiente:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Usuario recibe un link de invitación con un código único&lt;/li&gt;
&lt;li&gt;En la página, el usuario puede elegir entre iniciar sesión con Facebook o con Google&lt;/li&gt;
&lt;li&gt;Ya que se inicia la sesión, se redirecciona al usuario de regreso al sitio&lt;/li&gt;
&lt;li&gt;El usuario puede elegir si asistirá o no a la boda y si necesita llevar pareja&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Traducciones
&lt;/h3&gt;

&lt;p&gt;Como lo mencioné al principio, necesitamos traducciones para el sitio. Tenía muchas ganas de usar las traducciones nativas de Angular pero me hubiera tomado mucho tiempo configurarlas.&lt;/p&gt;

&lt;p&gt;Decidí ir por un paquete que usé mucho tiempo en mi trabajo anterior llamado &lt;a href="https://github.com/ngx-translate/core"&gt;@ngx-translate/core&lt;/a&gt;. Este paquete me permite generar variables y mantener los idiomas con base en archivos json. La configuración es muy corta y maneja el cambio de idioma de inmediato y a nivel de aplicación.&lt;/p&gt;

&lt;h3&gt;
  
  
  El producto terminado
&lt;/h3&gt;

&lt;p&gt;Al final el sitio terminó así:&lt;/p&gt;

&lt;p&gt;&lt;a href="///static/8737fb7920869e91e1d7c37fdfb444e8/8d0ff/julie-y-vic-home.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2eysFNQ5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://juliescript.dev/static/8737fb7920869e91e1d7c37fdfb444e8/b9e4f/julie-y-vic-home.png" alt="Julie y Vic home" title="Julie y Vic home" width="590" height="723"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="///static/dec2723af5977caf33f5de42187199f3/8d0ff/julie-y-vic-about.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vVSI5Guc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://juliescript.dev/static/dec2723af5977caf33f5de42187199f3/b9e4f/julie-y-vic-about.png" alt="Julie y Vic about" title="Julie y Vic about" width="590" height="507"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusiones
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;¿Lo volvería a hacer?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;La verdad es que si no fuera por la funcionalidad especial que queríamos para administrar a los usuarios, hubiera utilizado alguna herramienta ya existente para hacerlo. Incluso contratar Squarespace para usar la plantilla que reproduje.&lt;/p&gt;

&lt;p&gt;No queríamos lidiar con procesar formularios a mano o conservar datos de invitados, por eso el login con Facebook o Google fue muy importante y eso es algo que no vimos en otras plataformas para hacer sitios de boda.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Altervativas para tu propio sitio de boda&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Puedes usar una herramienta como &lt;a href="https://www.squarespace.com/"&gt;Squarespace&lt;/a&gt; o &lt;a href="https://www.wix.com/"&gt;Wix&lt;/a&gt; para hacer un sitio. Incluso hay portales exclusivos de bodas como &lt;a href="https://www.theknot.com/"&gt;The Knot&lt;/a&gt; que te permiten crear un pequeño sitio con links a todo lo que necesitas.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;¿Es necesario?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Probablemente no. Si tu boda puede llevarse con invitaciones normales y es la ruta que quieres tomar, es lo único que se necesita. Si quieres manejar todo con un evento de Facebook se puede. Todo depende de lo que quieras para mantener a tus invitados enterados de todos los detalles de tu evento.&lt;/p&gt;

&lt;p&gt;Me gustó mucho la experiencia de hacer el sitio de la boda. Mi prometido y yo nunca habíamos trabajado en un proyecto juntos, así que fue una bonita experiencia. Además esto nos ayudó a pensar en más detalles del evento y organizar a nuestros invitados de mejor manera.&lt;/p&gt;

&lt;p&gt;Lamentablemente tuvimos que posponer la boda debido al COVID-19 pero cuando tengamos una nueva fecha pondremos el sitio en línea.&lt;/p&gt;

</description>
      <category>angular</category>
      <category>rust</category>
      <category>español</category>
      <category>spanish</category>
    </item>
    <item>
      <title>Validación personalizada en Angular</title>
      <dc:creator>Julieta Campos Guzmán</dc:creator>
      <pubDate>Thu, 30 Jan 2020 13:42:00 +0000</pubDate>
      <link>https://dev.to/juliescript/validacion-personalizada-en-angular-e5d</link>
      <guid>https://dev.to/juliescript/validacion-personalizada-en-angular-e5d</guid>
      <description>&lt;p&gt;Angular viene ya con un muy buen número de validaciones para formularios. Te maneja que el campo requerido, que el mínimo, que el máximo, que si el campo debe de cumplir un patrón, de todo.&lt;/p&gt;

&lt;p&gt;Sin embargo, hay veces que necesitamos algo más, algo que no cabe dentro de los casos genéricos que vienen incluidos con Angular. He ahí donde entra la validación personalizada o los validadores.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Qué es un validador?
&lt;/h2&gt;

&lt;p&gt;Un validador, o validator en inglés, es una función que escribes para checar que tu formulario cheque alguna función en específico. Usualmente se crea en un archivo aparte y se importa al componente. También se puede probar para revisar que los casos sean correctos.&lt;/p&gt;

&lt;p&gt;Al crear un validador también creas nuevas categorías de errores, mismos que puedes usar en tus plantillas para mostrar mensajes de error y marcar el formulario como válido o inválido.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ok, ok, ahora vamos a hacer uno porque sigo sin entender
&lt;/h2&gt;

&lt;p&gt;El caso clásico para un validador personalizado es el de checar que un formulario para registrar una contraseña y luego confirmarla.&lt;/p&gt;

&lt;p&gt;Para crear este formulario vamos a usar una forma reactiva:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;form&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;group&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;password&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Validators&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;required&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;confirmarPassword&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Validators&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;required&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;validators&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;validarQueSeanIguales&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;En este caso estoy declarando dos campos en el formulario, ambos deben de ser requeridos y después el grupo de campos va a tener una validación para ver que sean iguales.&lt;/p&gt;

&lt;p&gt;Ahora toca hacer una plantilla sencilla para mostrar nuestros campos:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt; &lt;span class="na"&gt;[formGroup]=&lt;/span&gt;&lt;span class="s"&gt;"form"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;mat-form-field&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;matInput&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"password"&lt;/span&gt; &lt;span class="na"&gt;formControlName=&lt;/span&gt;&lt;span class="s"&gt;"password"&lt;/span&gt; &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"Contraseña"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/mat-form-field&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;br&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;mat-form-field&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;matInput&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"password"&lt;/span&gt; &lt;span class="na"&gt;formControlName=&lt;/span&gt;&lt;span class="s"&gt;"confirmarPassword"&lt;/span&gt; &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"Confirmar Contraseña"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/mat-form-field&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Nota:&lt;/strong&gt; En este ejemplo estoy usando Angular Material para darle estilo a la interfaz, pero no es necesario usar Material para hacer validadores personalizados.&lt;/p&gt;

&lt;p&gt;El siguiente paso es escribir nuestra función de validación. Esto lo voy a hacer en un archivo separado llamado &lt;code&gt;app.validator.ts&lt;/code&gt;, me gusta mucho usar la convención &lt;code&gt;&amp;lt;nombre_del_componente&amp;gt;.validator.ts&lt;/code&gt; para denotar mis validadores, pero depende del caso y la necesidad del proyecto. A veces los validadores se pueden llegar a compartir entre componentes, por lo cual es mejor idea llamarlos de acuerdo a lo que vayan a validar. También cabe notar que pueden haber varias funciones de validación dentro de un mismo archivo de validadores.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;FormGroup&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ValidationErrors&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ValidatorFn&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/forms&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;validarQueSeanIguales&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ValidatorFn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;control&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FormGroup&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;ValidationErrors&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;password&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;control&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;password&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;confirmarPassword&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;control&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;confirmarPassword&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;confirmarPassword&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;
        &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;
        &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;noSonIguales&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  ¿Qué está pasando aquí?
&lt;/h3&gt;

&lt;p&gt;Lo que estoy haciendo es definir una función de validación o &lt;code&gt;ValidatorFn&lt;/code&gt;, que recibe como parámetro un grupo de campos , &lt;code&gt;FormGroup&lt;/code&gt;, y va a regresa o un objeto de errores de validación, &lt;code&gt;ValidationErrors&lt;/code&gt;, o un &lt;code&gt;null&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Ya dentro de la función, podemos encontrar cada campo que necesitamos comparar. En este caso son los dos campos de nuestro formulario &lt;code&gt;password&lt;/code&gt; y &lt;code&gt;confirmarPassword&lt;/code&gt;. Posteriormente comparamos los valores de los campos y si son los mismos retornamos un &lt;code&gt;null&lt;/code&gt;. Si no es así, entonces se retorna el objeto con el error &lt;code&gt;{ noSonIguales: true }&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Con esto nuestro formulario va a saber si es válido o si tiene algún error.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Cómo despliego estos errores?
&lt;/h2&gt;

&lt;p&gt;Para desplegar estos errores, necesitamos indicarle a nuestra plantilla cuando hay un error de validación. En el caso de este validador, va a mostrar un error desde que empecemos a escribir en el primer campo. Esto no es ideal ya que el usuario se va a preguntar que cómo hizo algo malo si apenas empezó a llenar el formulario.&lt;/p&gt;

&lt;p&gt;Podemos combinar el resultado de nuestro validador con el estado de los campos del formulario.&lt;/p&gt;

&lt;p&gt;En Angular, los campos de un formulario tienen 4 estados: &lt;code&gt;pristine&lt;/code&gt;, &lt;code&gt;touched&lt;/code&gt;, &lt;code&gt;untouched&lt;/code&gt; y &lt;code&gt;dirty&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;En resumen quedan algo así:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;pristine&lt;/code&gt; - No se ha tenido interacción alguna con el campo&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;untouched&lt;/code&gt; - Si pusiste el cursor o fuiste al campo con la tecla de tabulador, sólo se activa cuando se llega al campo&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;touched&lt;/code&gt; - Si ya te fuiste del campo, ya cambiaste el cursor de lugar o seguiste a los demás campos&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;dirty&lt;/code&gt; - Si ya se tuvo interacción con el campo&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Nuestro usuario necesita saber si las contraseñas son iguales después de que empieza a escribir la confirmación. Así que voy a checar que ambos campos tengan estatus &lt;code&gt;dirty&lt;/code&gt; y checar si el formulario tiene el error de &lt;code&gt;noSonInguales&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;checarSiSonIguales&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hasError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;noSonIguales&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;password&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;dirty&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;confirmarPassword&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;dirty&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A mí me gusta hacer funciones que revisen estas cosas en lugar de tener toda la lógica en plantilla, pero si ponen la condición en la plantilla también funciona igual.&lt;/p&gt;

&lt;p&gt;En la plantilla queda así:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;mat-error&lt;/span&gt; &lt;span class="na"&gt;*ngIf=&lt;/span&gt;&lt;span class="s"&gt;"checarSiSonIguales()"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Las contraseñas no coinciden&lt;span class="nt"&gt;&amp;lt;/mat-error&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Así que cuando las contraseñas no coinciden, se va a mostrar un bonito mensaje de error en color rojo que dice &lt;code&gt;Las contraseñas no son iguales&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Incluso si queremos ir un paso más allá, podemos usar el estatus del formulario para bloquear un botón de &lt;code&gt;Enviar&lt;/code&gt; y una vez que nuestra forma esté libre de errores, habilitarlo y dejar al usuario enviar su formulario.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;mat-raised-button&lt;/span&gt; &lt;span class="na"&gt;[disabled]=&lt;/span&gt;&lt;span class="s"&gt;"!form.valid"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Enviar&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hay muchas otras formas para jugar con mensajes de error, clases, habilitar y deshabilitar campos y botones. Todo depende del formulario con el que se esté trabajando y las condiciones que necesita.&lt;/p&gt;

&lt;p&gt;Como siempre, acá les dejo un ejemplo en StackBlitz de este pequeño tutorial:&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/angular-6ec4zm?" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;En el siguiente tutorial, voy a hacer un formulario dinámico con varios tipos de validaciones para que vean como se pueden combinar.&lt;/p&gt;

</description>
      <category>angular</category>
      <category>forms</category>
      <category>validators</category>
      <category>spanish</category>
    </item>
    <item>
      <title>¿Cómo usar formularios dinámicos en Angular?</title>
      <dc:creator>Julieta Campos Guzmán</dc:creator>
      <pubDate>Sun, 06 Oct 2019 13:42:00 +0000</pubDate>
      <link>https://dev.to/juliescript/como-usar-formularios-dinamicos-en-angular-5bcm</link>
      <guid>https://dev.to/juliescript/como-usar-formularios-dinamicos-en-angular-5bcm</guid>
      <description>&lt;p&gt;&lt;strong&gt;Disclaimer&lt;/strong&gt;: Esta tarea la hice originalmente en Angular 7 y estamos en proceso de actualizar a Angular 8 por esta razón puede que las cosas cambien en versiones más recientes.&lt;/p&gt;




&lt;p&gt;Uno de los retos más raros que he tenido ha sido trabajar con formularios dinámicos en Angular.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Qué es un formulario dinámico?
&lt;/h3&gt;

&lt;p&gt;Un formulario dinámico es cuando un formulario permite a un usuario generar campos con una acción. El formulario nunca va a saber cuantos campos quiere tener un usuario, por lo que el usuario tiene todo el control sobre la cantidad de campos que se generan. El usuario también puede quitar campos y eso es lo que hace la forma dinámica.&lt;/p&gt;

&lt;p&gt;Un ejemplo es un típico formulario para hacer un currículum en internet. La parte de educación y experiencia laboral se ven algo como así:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fjuliescript%2Fgatsby-blog%2Fmaster%2Fcontent%2Fblog%2Fformularios-din%25C3%25A1micos-angular%2Fformulario_dinamico.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fjuliescript%2Fgatsby-blog%2Fmaster%2Fcontent%2Fblog%2Fformularios-din%25C3%25A1micos-angular%2Fformulario_dinamico.png" alt="Formulario de experiencia laboral"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Angular nos permite tener formularios dinámicos con su módulo de formularios reactivos o &lt;code&gt;ReactiveFormsModule&lt;/code&gt;. Un formulario reactivo es un tipo de formulario que se crea desde el controlador. En lugar de tener el formulario 100% en la plantilla, desde el controlador se crean los campos y se añaden características como las validaciones.&lt;/p&gt;

&lt;p&gt;Hacer formularios directo en la plantilla parece ser más fácil al principio, pero si se tiene un formulario muy complejo es mejor hacerlo con formularios reactivos. Además parece que los formularios de plantilla serán deprecados en versiones futuras de Angular.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Cómo se crea un formulario reactivo?
&lt;/h3&gt;

&lt;p&gt;Lo primero que hay que hacer es añadir el módulo de formularios reactivos a nuestro módulo.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;NgModule&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;      &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;BrowserModule&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/platform-browser&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ReactiveFormsModule&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/forms&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;AppComponent&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;  &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./app.component&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;NgModule&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;imports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;      &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="nx"&gt;BrowserModule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ReactiveFormsModule&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;declarations&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="nx"&gt;AppComponent&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;bootstrap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;    &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="nx"&gt;AppComponent&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AppModule&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Ya que tenemos el módulo importado, tendremos todas las herramientas para nuestro formulario dinámico disponibles en nuestra aplicación.&lt;/p&gt;

&lt;p&gt;Ahora en nuestro controlador, lo primero que hay que hacer es definir dos cosas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Un &lt;code&gt;FormBuilder&lt;/code&gt; que nos va a ayudar a construir el formulario&lt;/li&gt;
&lt;li&gt;Un &lt;code&gt;FormGroup&lt;/code&gt; que va a ser nuestro formulario&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Para el &lt;code&gt;FormBuilder&lt;/code&gt;, tenemos que definirlo en el constructor del componente.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kr"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;fb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FormBuilder&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Y el &lt;code&gt;FormGroup&lt;/code&gt; sólo lo definimos como una variable en el componente.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="nx"&gt;formulario&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FormGroup&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Después, usando el método de &lt;code&gt;ngOnInit()&lt;/code&gt;, mandamos llamar a la función que va a crear el formulario. Esta función se puede llamar como sea, yo la llamé &lt;code&gt;crearFormulario&lt;/code&gt; porque soy mega original.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="nf"&gt;crearFormulario&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;formulario&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;group&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;experienciaLaboral&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;FormControl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Si este fuera un formulario normal, con esto ya tendríamos un formulario con un campo, pero queremos un formulario dinámico así que hay que seguir. &lt;/p&gt;
&lt;h3&gt;
  
  
  ¿Cómo se hace un formulario dinámico?
&lt;/h3&gt;

&lt;p&gt;Ahora es tiempo de introducir otra herramienta del módulo de formularios reactivos, se llama &lt;code&gt;FormArray&lt;/code&gt;. Un &lt;code&gt;FormArray&lt;/code&gt; es un arreglo de &lt;code&gt;FormControl&lt;/code&gt;. Se comporta muy parecido a un arreglo normal y tiene ciertos métodos propios que hace muy sencillo agregar y quitar elementos del mismo. Para usarlo vamos a modificar nuestro método &lt;code&gt;crearFormulario&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="nf"&gt;crearFormulario&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;formulario&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;group&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;experienciaLaboral&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;array&lt;/span&gt;&lt;span class="p"&gt;([])&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Como &lt;code&gt;FormBuilder&lt;/code&gt; ya incluye todas estas herramientas, no necesitamos definir un nuevo &lt;code&gt;FormArray&lt;/code&gt; con &lt;code&gt;new FormArray([])&lt;/code&gt;. Los dos métodos son válidos, pero si ya tenemos el FormBuilder definido, hay que usarlo.&lt;/p&gt;

&lt;p&gt;A mi gusto personal, prefiero crear una función para añadir campos al &lt;code&gt;FormArray&lt;/code&gt; que definimos en el formulario inicial. En el caso de este ejemplo, voy a crear un &lt;code&gt;FormGroup&lt;/code&gt; con 3 campos, y cada uno de estos grupos será añadido al arreglo llamado experiencia laboral.&lt;/p&gt;

&lt;p&gt;Ahora les voy a dar un consejo buenísimo que aprendí en mi nuevo trabajo: hay que crear una función de &lt;code&gt;get&lt;/code&gt; para conseguir el arreglo y así no hacernos mil bolas a la hora de manipularlo.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="nf"&gt;experienciaLaboral&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;FormArray&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;formulario&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;experienciaLaboral&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;FormArray&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Este &lt;code&gt;get&lt;/code&gt; nos va a permitir manejar el arreglo de manera mucho más sencilla que escribir todo cada vez y además hará que el código sea mucho más legible para otros.&lt;/p&gt;

&lt;p&gt;Ya que tenemos nuestro &lt;code&gt;get&lt;/code&gt;, podemos proseguir a crear el grupo que le vamos a poner:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="nf"&gt;anadirExperienciaLaboral&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;trabajo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;group&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;empresa&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;FormControl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;puesto&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;FormControl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;descripcion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;FormControl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;experienciaLaboral&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;trabajo&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Cada vez que llamemos a &lt;code&gt;anadirExperienciaLaboral&lt;/code&gt; vamos a generar un &lt;code&gt;FormGroup&lt;/code&gt; con 3 campos: empresa, puesto y descripción. Ya que esté creado, se va a añadir al arreglo de &lt;code&gt;experienciaLaboral&lt;/code&gt;. Todo de una manera muy sencilla por todo el código que ya escribimos.&lt;/p&gt;

&lt;p&gt;No se te olvide añadir esta función a &lt;code&gt;ngOnInit&lt;/code&gt; justo abajo de la de &lt;code&gt;crearFormulario&lt;/code&gt; para añadir campos la primera vez.&lt;/p&gt;

&lt;p&gt;Ahora, ¿cómo lo vemos en la plantilla?&lt;/p&gt;
&lt;h3&gt;
  
  
  ¿Cómo es la plantilla de un formulario dinámico?
&lt;/h3&gt;

&lt;p&gt;La plantilla no es tan diferente que la de un formulario hecho con base en plantillas. Sin embargo, hay detalles que tenemos que tener en cuenta a la hora de generarlo.&lt;/p&gt;

&lt;p&gt;Una cosa que me tuvo atorada mucho tiempo, fue olvidar poner el nombre del arreglo en la plantilla antes de hacer un ciclo &lt;code&gt;for&lt;/code&gt; para generar los campos.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;

&lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt; &lt;span class="na"&gt;[formGroup]=&lt;/span&gt;&lt;span class="s"&gt;"formulario"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;formArrayName=&lt;/span&gt;&lt;span class="s"&gt;"experienciaLaboral"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;*ngFor=&lt;/span&gt;&lt;span class="s"&gt;"let trabajo of experienciaLaboral.controls"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;input&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;El atributo de &lt;code&gt;formArrayName&lt;/code&gt; es fundamental para que nuestra plantilla sepa que va a recibir un arreglo dentro del formulario. Si esto no se define, los campos no aparecerán en la plantilla.&lt;/p&gt;

&lt;p&gt;Otra cosa importante es que aunque tenemos nuestro &lt;code&gt;get&lt;/code&gt; para &lt;code&gt;experienciaLaboral&lt;/code&gt;, el &lt;code&gt;FormArray&lt;/code&gt; no funciona como un arreglo normal por el que podemos iterar. Por eso es importante definir que vamos a iterar por los controles del arreglo. Los controles son todos los &lt;code&gt;FormGroups&lt;/code&gt; que se han añadido al &lt;code&gt;FormArray&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Para mostrar los campos que queremos es necesario añadir el código para mostrarlos:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;

&lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt; &lt;span class="na"&gt;[formGroup]=&lt;/span&gt;&lt;span class="s"&gt;"formulario"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;h3&amp;gt;&lt;/span&gt;
    Experiencia Laboral:
  &lt;span class="nt"&gt;&amp;lt;/h3&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;formArrayName=&lt;/span&gt;&lt;span class="s"&gt;"experienciaLaboral"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;*ngFor=&lt;/span&gt;&lt;span class="s"&gt;"let trabajo of experienciaLaboral.controls"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;label&amp;gt;&lt;/span&gt;Empresa:&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&amp;lt;br&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;label&amp;gt;&lt;/span&gt;Puesto:&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&amp;lt;br&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;label&amp;gt;&lt;/span&gt;Descripción:&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&amp;lt;br&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;textarea&amp;gt;&amp;lt;/textarea&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;hr&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  ¿Cómo se vuelve este show dinámico?
&lt;/h3&gt;

&lt;p&gt;Como lo mencioné al principio, el chiste de los formularios dinámicos es que el usuario pueda añadir y quitar campos a voluntad. En el caso de este formulario, no se van a poder añadir o quitar campos individuales, sino todo un grupo completo a la vez.&lt;/p&gt;

&lt;p&gt;Para añadir más campos hay que crear un botón en la plantilla que llame a la función de &lt;code&gt;anadirExperienciaLaboral&lt;/code&gt;, algo así:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;

&lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;(click)=&lt;/span&gt;&lt;span class="s"&gt;"anadirExperienciaLaboral()"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  + Añadir
&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Este botón se puede poner afuera del &lt;code&gt;*ngFor&lt;/code&gt; para que aparezca una vez en la plantilla.&lt;/p&gt;

&lt;p&gt;En el caso de quitar campos del formulario, hay que agregar un botón para borrar dentro de cada grupo que añadimos. Pero primero hay que crear la función que se va a encargar de borrar en nuestro controlador.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="nf"&gt;borrarTrabajo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;indice&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;experienciaLaboral&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;removeAt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;indice&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Se podrán dar cuenta que la función que cree se llama &lt;code&gt;borrarTrabajo&lt;/code&gt; y que recibe un índice. Este índice es el mismo índice que tiene el grupo en el arreglo y para conseguirlo desde la plantilla hay que modificar nuestro &lt;code&gt;*ngFor&lt;/code&gt; de la siguiente manera:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;

&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;*ngFor=&lt;/span&gt;&lt;span class="s"&gt;"let trabajo of experienciaLaboral.controls; let i = index;"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Esa variable &lt;code&gt;i&lt;/code&gt; va a contener el índice, lo que le va a decir al método &lt;code&gt;removeAt&lt;/code&gt; cual elemento del arreglo tiene que borrar.&lt;/p&gt;

&lt;p&gt;En la plantilla el botón para borrar va de la siguiente manera:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;

&lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;(click)=&lt;/span&gt;&lt;span class="s"&gt;"borrarTrabajo(i)"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Borrar&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Y así es como ya se pueden añadir y borrar campos a nuestro formulario de manera dinámica.&lt;/p&gt;

&lt;p&gt;El código de este ejemplo se ve muy sencillo, pero la primera vez que lo tuve que hacer se me complicó muchísimo. En la documentación no estaba muy bien explicado como funcionan los &lt;code&gt;FormArray&lt;/code&gt;, tampoco como se muestran en la plantilla. Mucho menos había explicaciones sobre como validar todo esto para ver si el formulario estaba correcto antes de mandarlo. Este post sólo es la primera parte de una serie que puede ser enorme y que estaré escribiendo poco a poco.&lt;/p&gt;

&lt;p&gt;Aquí abajo les dejo el proyecto final en Glitch y lo estaré usando como base para los siguientes posts.&lt;/p&gt;


&lt;div class="glitch-embed-wrap"&gt;
  &lt;iframe src="https://glitch.com/embed/#!/embed/nonchalant-saturday?path=index.html" alt="nonchalant-saturday on glitch"&gt;&lt;/iframe&gt;
&lt;/div&gt;






&lt;p&gt;Espero que este pequeño ejemplo les sirva para entender mejor los formularios reactivos y dinámicos. Son herramientas muy útiles para hacer aplicaciones con funcionalidades más complejas. En la siguiente parte escribiré sobre validación y como crear validaciones dinámicas y como aplicarlas a diferentes partes del formulario.&lt;/p&gt;

</description>
      <category>angular</category>
      <category>formularios</category>
      <category>español</category>
      <category>spanish</category>
    </item>
  </channel>
</rss>
