<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[public_void]]></title><description><![CDATA[public_void]]></description><link>https://publicvoid.hashnode.dev</link><generator>RSS for Node</generator><lastBuildDate>Tue, 01 Sep 2026 05:32:58 GMT</lastBuildDate><atom:link href="https://publicvoid.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[SOLID 1: única responsabilidad (single responsibility)]]></title><description><![CDATA[Aprende el principio de única responsabilidad (SRP) en programación orientada a objetos y cómo puede ayudarte a crear código mas flexible y fácil de mantener.
[Publicado el 29 de Marzo, 2023 en rckstr1.github.io]
INTRODUCCIÓN
El principio de única re...]]></description><link>https://publicvoid.hashnode.dev/solid-1-unica-responsabilidad-single-responsibility</link><guid isPermaLink="true">https://publicvoid.hashnode.dev/solid-1-unica-responsabilidad-single-responsibility</guid><category><![CDATA[SOLID principles]]></category><category><![CDATA[single responsibility principle]]></category><category><![CDATA[clean code]]></category><category><![CDATA[software architecture]]></category><dc:creator><![CDATA[Adrian Gonzalez]]></dc:creator><pubDate>Sun, 02 Apr 2023 02:21:13 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1680401796242/fc75967c-deac-4005-9faf-f0663ed7b914.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Aprende el principio de única responsabilidad (SRP) en programación orientada a objetos y cómo puede ayudarte a crear código mas flexible y fácil de mantener.</p>
<p><a target="_blank" href="https://rckstr1.github.io/2023/03/29/SRP.html">[Publicado el 29 de Marzo, 2023 en rckstr1.github.io]</a></p>
<h2 id="heading-introduccion"><strong>INTRODUCCIÓN</strong></h2>
<p>El principio de única responsabilidad, Single Responsibility Principle (SRP) es el primero de los 5 principios SOLID y es esencial para crear codigo limpio y mantenible. En este post, exploramos el principio de única responsabilidad en más detalle, discutiendo por qué es importante, como aplicarlo en la práctica, y algunos ejemplos de como puede usarse para crear codigo más limpio.</p>
<h2 id="heading-principio-de-unica-responsabilidad-srp"><strong>PRINCIPIO DE ÚNICA RESPONSABILIDAD (SRP)</strong></h2>
<p>El principio de única responsabilidad (SRP) es un principio de diseño clave en la programación orientada a objetos que establece que una clase debe tener una sola responsabilidad o razón para cambiar. En otras palabras, una clase debe tener un solo trabajo o función, y debe hacerlo bien.</p>
<p>Al apegarse al principio de única responsabilidad, los desarrolladores podemos crear código que sea mas modular, flexible y mantenible. Si una clase tiene mas de una responsabilidad, se vuelve mas difícil de modificar, probar y reusar. Al dividir clases complejas en varias clases mas pequeñas y especializadas, podemos hacer que nuestro código sea mas facil de entender y modificar.</p>
<p>Por ejemplo, consideremos una clase que se encargue de la autenticación y manejo del perfil de un usuario:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">class</span> <span class="hljs-title">Usuario</span> {
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">login</span>(<span class="hljs-params">String username, String password</span>)</span> {
        <span class="hljs-comment">// ejecutar autenticacion</span>
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">actualizarPerfil</span>(<span class="hljs-params">String nombre, String apellido, String email</span>)</span> {
        <span class="hljs-comment">// ejecutar actualizacion de perfil</span>
    }
}
</code></pre>
<p>Esta clase infringe el principio de única responsabilidad porque tiene dos responsabilidades distintas: ejecutar la autenticacion y manejar el perfil del usuario. Para resolver esto, podemos dividir la clase Usuario en dos clases distintas: un Authenticador y un AdministradorPerfil:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">class</span> <span class="hljs-title">Autenticador</span> {
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">login</span>(<span class="hljs-params">String username, String password</span>)</span> {
        <span class="hljs-comment">// ejecuta autentication</span>
    }
}

<span class="hljs-keyword">class</span> <span class="hljs-title">AdministradorPerfil</span> {
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">actualizarPerfil</span>(<span class="hljs-params">String nombre, String apellido, String email</span>)</span> {
        <span class="hljs-comment">// ejecuta actualizacion</span>
    }
}
</code></pre>
<p>De esta manera, si necesitas cambiar la manera en que se ejecuta la autenticación, puedes modificar la clase Autenticador sin afectar la clase AdministradorPerfil.</p>
<p>En resumen, el principio de única responsabilidad (Single Responsibility Principle, SRP) es una herramienta poderosa para crear diseños de software mantenibles. Al seguir este y los otros principios SOLID, podemos crear sistemas que sean mas fáciles de mantener y escalar, reduciendo costos de desarrollo y mejorando la satisfacción del cliente. Asi que, si buscas mejorar tus habilidades de diseño de software, comienza por aplicar el principio de única responsabilidad a tu código y vé los beneficios por tí mismo.</p>
<p>Nos vemos en el siguiente post, donde cubriremos el segundo de los principios SOLID, principio de "Abierto-Cerrado" (Open-Closed Principle, OCP), que establece que las entidades de software deben ser abiertas a extensiones pero cerradas a modificaciones.</p>
<p>Happy coding!</p>
]]></content:encoded></item><item><title><![CDATA[¿Qué es SOLID?]]></title><description><![CDATA[[Publicado el 5 de Noviembre, 2019 en rckstr1.github.io]
INTRODUCCIÓN
Los principales lenguajes modernos de programación están influenciados por el paradigma orientado a objetos. Pero, ¿qué es el diseño orientado a objetos? ¿Cuáles son sus ventajas y...]]></description><link>https://publicvoid.hashnode.dev/que-es-solid</link><guid isPermaLink="true">https://publicvoid.hashnode.dev/que-es-solid</guid><category><![CDATA[SOLID principles]]></category><category><![CDATA[software design]]></category><category><![CDATA[software architecture]]></category><category><![CDATA[clean code]]></category><dc:creator><![CDATA[Adrian Gonzalez]]></dc:creator><pubDate>Sun, 02 Apr 2023 02:14:33 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1680401409163/c19f834f-73ae-4d41-b05f-414c8124e1a2.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><a target="_blank" href="https://rckstr1.github.io/2019/11/05/SOLID-Intro.html">[Publicado el 5 de Noviembre, 2019 en rckstr1.github.io]</a></p>
<h2 id="heading-introduccion"><strong>INTRODUCCIÓN</strong></h2>
<p>Los principales lenguajes modernos de programación están influenciados por el paradigma orientado a objetos. Pero, ¿qué es el diseño orientado a objetos? ¿Cuáles son sus ventajas y desventajas?</p>
<p>Comúnmente los desarrolladores no podemos contestar estas preguntas ni tenemos presentes los principios que constituyen la base de las disciplinas de las que derivaron nuestros lenguajes de programación.</p>
<p>Podríamos afirmar que virtualmente todos los desarrolladores de software utilizan algún tipo de lenguaje orientado a objetos. Sin embargo, la mayoría, usamos estos lenguajes sin saber por qué, y sin saber cómo obtener el mayor beneficio del diseño orientado a objetos.</p>
<h2 id="heading-que-es-solid"><strong>¿QUÉ ES SOLID?</strong></h2>
<p>SOLID es un acrónimo para los primeros 5 de 11 principios del diseño orientado a objetos que exponen el manejo de dependencias, presentados por Robert C. Martin, también conocido como “Uncle Bob”.</p>
<p>Los primeros 5 principios del diseño orientado a objetos se refieren al diseño de clases.</p>
<table><tbody><tr><td><p><strong>SINGLE RESPONSIBILITY PRINCIPLE</strong></p></td><td><p>Principio de responsabilidad única</p></td><td><p><em>"Una clase debe tener una, y solo una, razón para cambiar"</em></p></td></tr><tr><td><p><strong>OPEN CLOSED PRINCIPLE</strong></p></td><td><p>Principio de abierto/cerrado</p></td><td><p><em>"Debes ser capaz de extender el comportamiento de una clase sin modificarla"</em></p></td></tr><tr><td><p><strong>LISKOV SUBSTITUTION PRINCIPLE</strong></p></td><td><p>Principio de sustitución de Liskov</p></td><td><p><em>"Las clases derivadas deben ser sustituibles por sus clases base"</em></p></td></tr><tr><td><p><strong>INTERFACE SEGREGATION PRINCIPLE</strong></p></td><td><p>Principio de segregación de interfaces</p></td><td><p><em>"Diseña interfaces pequeñas que sean especificas del cliente"</em></p></td></tr><tr><td><p><strong>DEPENDENCY INVERSION PRINCIPLE</strong></p></td><td><p>Principio de inversión de dependencias</p></td><td><p><em>"Depende de abstracciones, no de concreciones"</em></p></td></tr></tbody></table>

<p>Apegarse a los principios SOLID, nos facilita a los desarrolladores escribir software fácil de mantener y extender. También nos ayuda a prevenir malas prácticas, a facilitar refactorización de código y también fomenta el desarrollo ágil de software.</p>
<p>En los siguientes posts exploraremos cada uno de los 5 principios SOLID para presentar los beneficios que brindan y ayudar a identificar las áreas de oportunidad para implementarlos, así como tomar en cuenta el posible costo de aumentar complejidad a nuestro código contra el beneficio de tener código más apegado a estos principios.</p>
<p>En resumen, aplicar los principios solid de manera adecuada nos permite tener código limpio, que se traduce en sistemas más flexibles y estables.</p>
<p>¡Hasta la próxima amigos!</p>
<h2 id="heading-fuentes"><strong>FUENTES</strong></h2>
<ul>
<li><p>Pluralsight. “SOLID Principles of Object Oriented Design”. <a target="_blank" href="https://app.pluralsight.com/library/courses/principles-oo-design/table-of-contents">https://app.pluralsight.com/library/courses/principles-oo-design/table-of-contents</a></p>
</li>
<li><p><a target="_blank" href="http://butUncleBob.com">butUncleBob.com</a>. “The principles of OOD”. <a target="_blank" href="http://butunclebob.com/ArticleS.UncleBob.PrinciplesOfOod">http://butunclebob.com/ArticleS.UncleBob.PrinciplesOfOod</a></p>
</li>
</ul>
<h2 id="heading-creditos"><strong>CRÉDITOS</strong></h2>
<ul>
<li>Elementos de diseño en el banner. <a target="_blank" href="http://www.freepik.com/">Designed by</a> <a target="_blank" href="http://rawpixel.com">rawpixel.com</a> <a target="_blank" href="http://www.freepik.com/">/ Freepik</a></li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Gráficas con ng2-charts (chart.js) y angular 8. Ordena, filtra, mapea y reduce arreglos de objetos]]></title><description><![CDATA[[Publicado el 6 de Septiembre, 2019 en rckstr1.github.io]
INTRODUCCIÓN
Esta es la cuarta y última parte de la serie de posts “GLTrack”. Durante los 4 posts hemos construido una aplicación que permite a los pacientes de diabetes llevar un registro de ...]]></description><link>https://publicvoid.hashnode.dev/graficas-con-ng2-charts-chartjs-y-angular-8-ordena-filtra-mapea-y-reduce-arreglos-de-objetos</link><guid isPermaLink="true">https://publicvoid.hashnode.dev/graficas-con-ng2-charts-chartjs-y-angular-8-ordena-filtra-mapea-y-reduce-arreglos-de-objetos</guid><category><![CDATA[Angular]]></category><category><![CDATA[material ui]]></category><dc:creator><![CDATA[Adrian Gonzalez]]></dc:creator><pubDate>Sun, 02 Apr 2023 02:09:04 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1680400365192/7364d0dc-e6b7-434b-a0a7-0bc85ca89556.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><a target="_blank" href="https://rckstr1.github.io/2019/09/06/GLTrack4.html">[Publicado el 6 de Septiembre, 2019 en rckstr1.github.io]</a></p>
<h2 id="heading-introduccion"><strong>INTRODUCCIÓN</strong></h2>
<p>Esta es la cuarta y última parte de la serie de posts “GLTrack”. Durante los 4 posts hemos construido una aplicación que permite a los pacientes de diabetes llevar un registro de sus mediciones diarias de niveles de glucosa en la sangre.</p>
<p>En el post anterior, comenzamos a construir la página principal de la aplicación e implementamos un componente que muestra una tabla con los datos de niveles de glucosa capturador por el usuario.</p>
<p>Hoy implementaremos gráficas de línea, barras y pastel para representar de manera visual los datos cargados en el sistema.</p>
<p>Comenzaremos corrigiendo un bug que encontré mientras trabajaba en este post. El bug quedó corregido también en los repositorios de GitHub de los posts anteriores.</p>
<h4 id="heading-nota-esta-es-la-parte-4-de-4-de-la-serie-de-posts-gltrack"><strong>NOTA: ESTA ES LA PARTE 4 DE 4 DE LA SERIE DE POSTS "GLTRACK"</strong></h4>
<ul>
<li><p><a target="_blank" href="https://rckstr1.github.io/2019/06/18/GLTrack1.html">GLTrack parte 1: "Schematics, Componentes y Ruteo con Angular + Material".</a></p>
</li>
<li><p><a target="_blank" href="https://rckstr1.github.io/2019/08/07/GLTrack2.html">GLTrack parte 2: "Modelos, servicios, dependency injection, formas y data binding con Angular + Material".</a></p>
</li>
<li><p><a target="_blank" href="https://rckstr1.github.io/2019/08/22/GLTrack3.html">GLTrack parte 3: "Reutiliza componentes. Interacción entre componentes usando @Input() y EventEmmiter con Angular 8".</a></p>
</li>
<li><p><a target="_blank" href="https://rckstr1.github.io/2019/09/06/GLTrack4.html">GLTrack parte 4: "Gráficas con ng2-charts (Chart.js) y Angular 8. Ordena, filtra, mapea y reduce arreglos de objetos.".</a></p>
</li>
</ul>
<h2 id="heading-paso-0-corregir-bug-en-el-componente-tabla-registros"><strong>PASO 0: CORREGIR BUG EN EL COMPONENTE “TABLA-REGISTROS”</strong></h2>
<p>El bug consiste en que la paginación de la tabla de registros no funciona correctamente. Esto es causado por que los elementos del paginador y el sorteador se conectan a la fuente de datos de la tabla en el constructor del componente.</p>
<p>Para corregir esto, debemos mover este código al método ngOnInit(). Modifica el siguiente código en “tabla-registros.component.ts”:</p>
<pre><code class="lang-typescript">...
dataSource = <span class="hljs-keyword">new</span> MatTableDataSource&lt;MedicionGlucosa&gt;(<span class="hljs-built_in">this</span>._registros);
...
<span class="hljs-keyword">constructor</span>(<span class="hljs-params"></span>) {
}

ngOnInit() {
    <span class="hljs-built_in">this</span>.dataSource.paginator = <span class="hljs-built_in">this</span>.paginator;
    <span class="hljs-built_in">this</span>.dataSource.sort = <span class="hljs-built_in">this</span>.sort;
}
...
</code></pre>
<p><img src="https://rckstr1.github.io/images/blog/GLTrack4/01-BugFix.png" alt /></p>
<p>El primer cambio consiste en declarar e inicializar la tabla con los datos en la propiedad “this._registros”.</p>
<p>Después eliminamos todo el contenido del método constructor del componente y lo pasamos al método “ngOnInit()”. Ya no es necesario inicializar los datos de la tabla así que solo dejamos el código que conecta el paginador y el sorteador a la tabla.</p>
<p>Después de hacer estos cambios, el paginador de la tabla funciona correctamente.</p>
<h2 id="heading-paso-1-generar-registros-de-prueba-opcional"><strong>PASO 1: GENERAR REGISTROS DE PRUEBA (OPCIONAL)</strong></h2>
<p>Para generar registros con datos aleatorios para visualizarlos en las gráficas que implementaremos en el dashboard, agrega el siguiente código en el servicio “mediciones.service.ts”:</p>
<pre><code class="lang-typescript">...
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> MedicionesService {
    debugMode = <span class="hljs-literal">true</span>;

    ...

    <span class="hljs-keyword">constructor</span>(<span class="hljs-params"></span>) {
        ...
        <span class="hljs-keyword">if</span> (<span class="hljs-built_in">this</span>.debugMode) {
            <span class="hljs-built_in">this</span>.CrearDatosDePrueba();
        }
    }

    ...

    <span class="hljs-keyword">private</span> CrearDatosDePrueba() {
        <span class="hljs-keyword">if</span> (<span class="hljs-built_in">this</span>.GetAll().length &lt; <span class="hljs-number">2000</span>) {
            <span class="hljs-built_in">localStorage</span>.setItem(<span class="hljs-built_in">this</span>.storageKey, <span class="hljs-built_in">JSON</span>.stringify([] <span class="hljs-keyword">as</span> MedicionGlucosa[]));
            <span class="hljs-keyword">const</span> fechaA = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>();
            <span class="hljs-keyword">const</span> fechaB = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>();
            fechaA.setMonth(fechaA.getMonth() - <span class="hljs-number">24</span>);

            <span class="hljs-keyword">while</span> (fechaA &lt; fechaB) {
                <span class="hljs-keyword">let</span> medicion = <span class="hljs-built_in">this</span>.CrearMedicionRandom(<span class="hljs-string">'Desayuno'</span>, fechaA);
                <span class="hljs-built_in">this</span>.Create(medicion);
                medicion = <span class="hljs-built_in">this</span>.CrearMedicionRandom(<span class="hljs-string">'Comida'</span>, fechaA);
                <span class="hljs-built_in">this</span>.Create(medicion);
                medicion = <span class="hljs-built_in">this</span>.CrearMedicionRandom(<span class="hljs-string">'Cena'</span>, fechaA);
                <span class="hljs-built_in">this</span>.Create(medicion);
                fechaA.setDate(fechaA.getDate() + <span class="hljs-number">1</span>);
            }
        }
    }

    <span class="hljs-keyword">private</span> CrearMedicionRandom(comida: <span class="hljs-built_in">string</span>, fecha: <span class="hljs-built_in">Date</span>) {
        <span class="hljs-keyword">let</span> rnd = (<span class="hljs-built_in">Math</span>.random() * <span class="hljs-number">130</span>) + <span class="hljs-number">60</span>;
        <span class="hljs-keyword">const</span> nivelGlucosa = rnd;

        rnd = (<span class="hljs-built_in">Math</span>.floor(<span class="hljs-built_in">Math</span>.random() * <span class="hljs-number">100</span>) % <span class="hljs-number">2</span>);
        <span class="hljs-keyword">const</span> antesODespues = rnd === <span class="hljs-number">0</span> ? <span class="hljs-string">'Antes'</span> : <span class="hljs-string">'Despues'</span>;

        <span class="hljs-keyword">const</span> medicion: MedicionGlucosa = {
            Id: <span class="hljs-built_in">this</span>.NewGuid(),
            Timestamp: <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>(),
            Nivel: nivelGlucosa,
            Comida: comida,
            AntesDespues: antesODespues,
            Fecha: fecha
        };

        <span class="hljs-keyword">return</span> medicion;
    }
}
</code></pre>
<p><img src="https://rckstr1.github.io/images/blog/GLTrack4/02-UpdateService.png" alt /></p>
<p><img src="https://rckstr1.github.io/images/blog/GLTrack4/03-DummyRecords.png" alt /></p>
<p>Los cambios consisten en lo siguiente:</p>
<ol>
<li><p>Creamos una propiedad booleana “debugMode”.</p>
</li>
<li><p>En el método constructor, si la propiedad “debugMode” es igual a “true” el servicio va a precargar datos de prueba en la aplicación llamando al método “CrearDatosDePrueba()”.</p>
</li>
<li><p>El método “CrearDatosDePrueba()” genera 3 registros diarios de mediciones por cada día de los últimos 2 años utilizando el método “CrearMedicionRandom()”.</p>
</li>
<li><p>El método “CrearMedicionRandom()” genera valores pseudoaleatorios para generar registros de niveles de glucosa que se encuentren dentro de rangos realistas.</p>
</li>
</ol>
<p>Para deshabilitar este comportamiento, cambia el valor de la propiedad “debugMode” a “false”.</p>
<h2 id="heading-paso-2-actualizar-estilos-en-el-dashboard-de-la-aplicacion"><strong>PASO 2: ACTUALIZAR ESTILOS EN EL DASHBOARD DE LA APLICACIÓN</strong></h2>
<p>La página principal de la aplicación debe mostrar el contenido de manera ordenada para que todos los datos y graficas sean más fácil de entender. Para esto vamos a agregar los siguientes estilos en el archivo “dashboard.component.css”:</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.flex-row</span> {
    <span class="hljs-attribute">display</span>: flex;
    <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
    <span class="hljs-attribute">flex-wrap</span>: wrap;
    <span class="hljs-attribute">padding-bottom</span>: <span class="hljs-number">20px</span>;
}

<span class="hljs-selector-class">.flex-row-item</span><span class="hljs-selector-class">.uno</span> {
    <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
}

<span class="hljs-selector-class">.flex-row-item</span><span class="hljs-selector-class">.dos</span> {
    <span class="hljs-attribute">width</span>: <span class="hljs-number">50%</span>;
}

<span class="hljs-selector-class">.flex-row-item</span> <span class="hljs-selector-tag">mat-card</span> {
    <span class="hljs-attribute">margin-right</span>: <span class="hljs-number">10px</span>;
}

<span class="hljs-selector-class">.flex-row-item</span><span class="hljs-selector-pseudo">:last-child</span> <span class="hljs-selector-tag">mat-card</span> {
    <span class="hljs-attribute">margin-right</span>: <span class="hljs-number">0px</span>;
}
</code></pre>
<p>Ahora agregaremos algunos componentes “mat-card” de Angular Material que nos servirán como contenedores para las gráficas que se van a mostrar en la aplicación. Actualiza el contenido de “dashboard.component.html”:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"flex-row"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"flex-row-item uno"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">mat-card</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>RCKSTR1.GitHub.io<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">mat-card</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"flex-row"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"flex-row-item dos"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">mat-card</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>RCKSTR1.GitHub.io<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">mat-card</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"flex-row-item dos"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">mat-card</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>RCKSTR1.GitHub.io<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">mat-card</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"flex-row"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"flex-row-item uno"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">mat-card</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">mat-card-title</span>&gt;</span>Mis registros<span class="hljs-tag">&lt;/<span class="hljs-name">mat-card-title</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">app-tabla-registros</span> [<span class="hljs-attr">permitirEliminar</span>]=<span class="hljs-string">"false"</span> [<span class="hljs-attr">registros</span>]=<span class="hljs-string">"registros"</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">app-tabla-registros</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">mat-card</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p><a target="_blank" href="https://rckstr1.github.io/images/blog/GLTrack4/04-DashboardLayout.png"><img src="https://rckstr1.github.io/images/blog/GLTrack4/04-DashboardLayout.png" alt /></a></p>
<h2 id="heading-paso-3-instalar-ng2-charts-y-chartjs"><strong>PASO 3: INSTALAR NG2-CHARTS Y CHART.JS</strong></h2>
<p>Ng2-charts es un paquete de directivas de Angular para Chart.js que estaremos utilizando para crear graficas en Angular 8 utilizaremos ng2-charts.</p>
<p>En la terminal, ejecuta los siguientes comandos:</p>
<h4 id="heading-instala-ng2-charts"><strong>INSTALA NG2-CHARTS</strong></h4>
<pre><code class="lang-bash">npm install --save ng2-charts
</code></pre>
<h4 id="heading-instala-chartjs"><strong>INSTALA CHART.JS</strong></h4>
<pre><code class="lang-bash">npm install --save chart.js
</code></pre>
<h4 id="heading-importa-ng2-charts"><strong>IMPORTA NG2-CHARTS</strong></h4>
<p>Agrega el siguiente código en “App.module.ts”:</p>
<pre><code class="lang-typescript">...    
<span class="hljs-keyword">import</span> { ChartsModule } <span class="hljs-keyword">from</span> <span class="hljs-string">'ng2-charts'</span>;

<span class="hljs-meta">@NgModule</span>({
    declarations: [
        ...
    ],
    imports: [
        ...
        ChartsModule
    ],
    ...
})
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> AppModule { }
</code></pre>
<p><img src="https://rckstr1.github.io/images/blog/GLTrack4/05-ImportChartModule.png" alt /></p>
<h4 id="heading-instala-los-schematics-de-ng2-charts-para-generar-componentes-que-implementen-graficas-mas-rapidamente"><strong>INSTALA LOS SCHEMATICS DE NG2-CHARTS PARA GENERAR COMPONENTES QUE IMPLEMENTEN GRAFICAS MÁS RÁPIDAMENTE.</strong></h4>
<pre><code class="lang-bash">npm install --save-dev ng2-charts-schematics
</code></pre>
<h2 id="heading-paso-4-crear-graficas-utilizando-schematics-de-ng2-charts"><strong>PASO 4: CREAR GRÁFICAS UTILIZANDO SCHEMATICS DE NG2-CHARTS</strong></h2>
<p>A continuación, generaremos de manera automática componentes con implementaciones de gráficas de Charts.js utilizando los schematics que instalamos en el paso anterior. Ejecuta los siguientes comandos en la terminal para generar los nuevos componentes:</p>
<pre><code class="lang-bash">ng generate ng2-charts-schematics:line components/historico-mediciones-chart
ng generate ng2-charts-schematics:bar components/comparativo-mensual-chart
ng generate ng2-charts-schematics:pie components/global-niveles-chart
</code></pre>
<p><img src="https://rckstr1.github.io/images/blog/GLTrack4/06-NuevosComponentes.png" alt /></p>
<h3 id="heading-implementar-los-nuevos-componentes-al-dashboard"><strong>IMPLEMENTAR LOS NUEVOS COMPONENTES AL DASHBOARD</strong></h3>
<p>Para mostrar los componentes que acabamos de generar, actualiza el contenido de “dashboard.component.html”:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"flex-row"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"flex-row-item uno"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">mat-card</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">app-historico-mediciones-chart</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">app-historico-mediciones-chart</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">mat-card</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"flex-row"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"flex-row-item dos"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">mat-card</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">app-comparativo-mensual-chart</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">app-comparativo-mensual-chart</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">mat-card</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"flex-row-item dos"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">mat-card</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">app-global-niveles-chart</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">app-global-niveles-chart</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">mat-card</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
...
</code></pre>
<p><img src="https://rckstr1.github.io/images/blog/GLTrack4/07-BoilerplateCharts.png" alt /></p>
<p>Ahora se muestran los nuevos componentes que acabamos de generar.</p>
<h2 id="heading-paso-5-configurar-las-graficas"><strong>PASO 5: CONFIGURAR LAS GRAFICAS</strong></h2>
<p>En este paso modificaremos los componentes que incluyen las gráficas para ajustar aspectos estéticos, pero también para que los componentes reciban y procesen los datos que alimentan nuestras graficas.</p>
<h3 id="heading-actualizar-componente-historico-mediciones-chart"><strong>ACTUALIZAR COMPONENTE “HISTÓRICO-MEDICIONES-CHART”</strong></h3>
<p>Comenzaremos a modificar la primera gráfica, ajustando la altura a 100 en el archivo “histórico-mediciones-chart.component.html”:</p>
<p><a target="_blank" href="https://rckstr1.github.io/images/blog/GLTrack4/08-ChartHeight.png"><img src="https://rckstr1.github.io/images/blog/GLTrack4/08-ChartHeight.png" alt /></a></p>
<p>Para que el componente sea capaz de recibir y procesar los datos de las mediciones guardadas por el usuario, actualiza el archivo “historico-mediciones-chart.component.ts”:</p>
<pre><code class="lang-typescript">...
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> HistoricoMedicionesChartComponent <span class="hljs-keyword">implements</span> OnInit {
    <span class="hljs-keyword">public</span> lineChartData: ChartDataSets[] = [
        { data: [], label: <span class="hljs-string">'Nivel de glucosa'</span> },
    ];
    <span class="hljs-keyword">public</span> lineChartLabels: Label[] = [];
    <span class="hljs-keyword">public</span> lineChartOptions: ChartOptions = {
        responsive: <span class="hljs-literal">true</span>,
        scales: {
            xAxes: [{
                display: <span class="hljs-literal">false</span>
            }]
        }
    };
    ...
    <span class="hljs-meta">@Input</span>()
    set mediciones(datos: MedicionGlucosa[]) {
        <span class="hljs-keyword">const</span> fechaInicial = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>();
        fechaInicial.setMonth(fechaInicial.getMonth() - <span class="hljs-number">1</span>);

        <span class="hljs-keyword">const</span> ultimoMes = datos.filter(<span class="hljs-function"><span class="hljs-params">f</span> =&gt;</span> 
            <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>(<span class="hljs-built_in">Date</span>.parse(f.Fecha.toString())) &gt;= fechaInicial);

        <span class="hljs-built_in">this</span>.lineChartData[<span class="hljs-number">0</span>].data = ultimoMes.map(<span class="hljs-function"><span class="hljs-params">m</span> =&gt;</span> m.Nivel);
        <span class="hljs-built_in">this</span>.lineChartLabels = ultimoMes
            .map(<span class="hljs-function"><span class="hljs-params">m</span> =&gt;</span> <span class="hljs-string">`<span class="hljs-subst">${m.Comida}</span> <span class="hljs-subst">${m.AntesDespues}</span> <span class="hljs-subst">${<span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>(<span class="hljs-built_in">Date</span>.parse(m.Fecha.toString())).toDateString()}</span>`</span>);
    }
}
</code></pre>
<p><img src="https://rckstr1.github.io/images/blog/GLTrack4/09-HistoricoChartCode.png" alt /></p>
<p>Los cambios consisten en lo siguiente:</p>
<ol>
<li><p>Eliminar los datos precargados en el componente y actualizar la etiqueta principal.</p>
</li>
<li><p>Eliminar las etiquetas precargadas en el componente.</p>
</li>
<li><p>Configurar la gráfica para que no muestre las etiquetas en el eje X (opcional).</p>
</li>
<li><p>Agregar una propiedad de entrada “mediciones” con una función setter.</p>
<p> Esta función intercepta los valores de la propiedad “mediciones” y se ejecuta cada vez que el valor cambia. En este caso, cuando el valor de “mediciones” cambia, la gráfica se actualiza para mostrar los valores de todas las mediciones del último mes.</p>
</li>
</ol>
<h4 id="heading-el-metodo-filter"><strong>EL MÉTODO FILTER()</strong></h4>
<p>En la función setter de “mediciones” filtramos los objetos del arreglo “datos” por fecha para guardar en la constante “ultimoMes” solamente los registros del último mes (línea 49). Para esto utilizamos el método filter().</p>
<p>El método filter() crea un nuevo array con todos los elementos que cumplan la condición implementada por la función dada.</p>
<p>En este caso, primero guardamos la fecha actual en la constante “fechaInicial” y le restamos 1 mes. Después, la función dada a datos.filter() evalúa que la fecha de cada registro sea mayor o igual a la guardada en “fechaInicial”.</p>
<h4 id="heading-el-metodo-map"><strong>EL MÉTODO MAP()</strong></h4>
<p>Puedes observar que en la función setter de “mediciones” también utilizamos el método map() para crear un arreglo de los niveles de glucosa a partir del arreglo de objetos de tipo MedicionGlucosa (línea 51).</p>
<p>El método map() crea un nuevo array con los resultados de la llamada a la función indicada aplicados a cada uno de sus elementos.</p>
<p>En este caso, la función regesa el valor de la propiedad “Nivel” de cada una de las mediciones en el arreglo.</p>
<h3 id="heading-pasar-los-datos-de-la-aplicacion-desde-el-dashboard-al-componente"><strong>PASAR LOS DATOS DE LA APLICACIÓN DESDE EL DASHBOARD AL COMPONENTE</strong></h3>
<p>Ahora necesitamos pasar los registros de la aplicación a nuestro componente a través de la propiedad de entrada “mediciones”. Actualiza el archivo “dashboard.component.html”:</p>
<p>De esta manera, el dashboard pasa los datos de la aplicación al componente de la gráfica a través de la propiedad de entrada “mediciones”.</p>
<p><img src="https://rckstr1.github.io/images/blog/GLTrack4/10-HistoricoChartInput.png" alt /></p>
<h3 id="heading-actualizar-componente-comparativo-mensual-chart"><strong>ACTUALIZAR COMPONENTE “COMPARATIVO-MENSUAL-CHART”</strong></h3>
<p>Igual que con el componente anterior, eliminaremos los datos precargados en la gráfica. Modifica el código del archivo “comparativo-mensual-chart.component.ts”:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> ComparativoMensualChartComponent <span class="hljs-keyword">implements</span> OnInit {
    ...
    <span class="hljs-keyword">public</span> barChartLabels: Label[] = [];
    ...
    <span class="hljs-keyword">public</span> barChartData: ChartDataSets[] = [];

    nombreMeses = [
        <span class="hljs-string">'Enero'</span>, <span class="hljs-string">'Febrero'</span>, <span class="hljs-string">'Marzo'</span>, <span class="hljs-string">'Abril'</span>, <span class="hljs-string">'Mayo'</span>, <span class="hljs-string">'Junio'</span>, <span class="hljs-string">'Julio'</span>,
        <span class="hljs-string">'Agosto'</span>, <span class="hljs-string">'Septiembre'</span>, <span class="hljs-string">'Octubre'</span>, <span class="hljs-string">'Noviembre'</span>, <span class="hljs-string">'Diciembre'</span>
    ];
    ...
}
</code></pre>
<p><img src="https://rckstr1.github.io/images/blog/GLTrack4/11-ComparativoChartCodeA.png" alt /></p>
<p>Estos cambios consisten en:</p>
<ol>
<li><p>Eliminar las etiquetas precargadas en el componente.</p>
</li>
<li><p>Eliminar los datos precargados en el componente.</p>
</li>
<li><p>Crear la propiedad “nombreMeses” que contiene un arreglo con los nombres de los meses del año.</p>
</li>
</ol>
<p>Ahora, para mostrar los datos comparativos de cada mes, crearemos una propiedad de entrada “mediciones” con una función setter en el archivo “comparativo-mensual-chart.component.ts”:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> ComparativoMensualChartComponent <span class="hljs-keyword">implements</span> OnInit {
    ...
    <span class="hljs-meta">@Input</span>()
    set mediciones(datos: MedicionGlucosa[]) {
        <span class="hljs-comment">// Ordenar los datos por fecha</span>
        datos.sort(<span class="hljs-function">(<span class="hljs-params">a, b</span>) =&gt;</span> {
            <span class="hljs-keyword">return</span> <span class="hljs-built_in">Date</span>.parse(a.Fecha.toString()) - <span class="hljs-built_in">Date</span>.parse(b.Fecha.toString());
        });

        <span class="hljs-comment">// Obtener un arreglo de años disponibles</span>
        <span class="hljs-keyword">let</span> anos = datos.map(<span class="hljs-function"><span class="hljs-params">m</span> =&gt;</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>(m.Fecha.toString()).getFullYear());
        <span class="hljs-comment">// Filtrar duplicados</span>
        anos = anos.filter(<span class="hljs-function">(<span class="hljs-params">val, i</span>) =&gt;</span> anos.indexOf(val) === i);

        <span class="hljs-keyword">const</span> anoActual = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>().getFullYear();
        <span class="hljs-keyword">const</span> anoAnterior = anoActual - <span class="hljs-number">1</span>;

        <span class="hljs-comment">// Eliminar datos existentes en la gráfica</span>
        <span class="hljs-built_in">this</span>.barChartData = [{ label: anoAnterior.toString(), data: [] }, { label:
        anoActual.toString(), data: [] }];
        <span class="hljs-built_in">this</span>.barChartLabels = [];

        <span class="hljs-keyword">const</span> mesActual = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>().getMonth();
        <span class="hljs-keyword">let</span> iMes = <span class="hljs-number">0</span>;

        <span class="hljs-keyword">while</span> (iMes &lt;= mesActual) {
            <span class="hljs-comment">// Agregar etiquetas con los nombres de cada mes desde Enero hasta el mes actual</span>
            <span class="hljs-built_in">this</span>.barChartLabels.push(<span class="hljs-built_in">this</span>.nombreMeses[iMes]);

            <span class="hljs-comment">// Obtener promedio mensual del año actual y el anterior</span>
            <span class="hljs-built_in">this</span>.barChartData[<span class="hljs-number">0</span>].data.push(<span class="hljs-built_in">this</span>.getPromedioMediciones(anoAnterior, iMes, datos));
            <span class="hljs-built_in">this</span>.barChartData[<span class="hljs-number">1</span>].data.push(<span class="hljs-built_in">this</span>.getPromedioMediciones(anoActual, iMes, datos));

            iMes++;
        }
    }

    getPromedioMediciones(ano: <span class="hljs-built_in">number</span>, mes: <span class="hljs-built_in">number</span>, datos: MedicionGlucosa[]) {
        <span class="hljs-keyword">let</span> promedio = <span class="hljs-number">0</span>;
        <span class="hljs-keyword">let</span> datosFiltrados: MedicionGlucosa[] = [];
        <span class="hljs-keyword">let</span> cantidadMediciones = <span class="hljs-number">0</span>;
        <span class="hljs-keyword">let</span> suma = <span class="hljs-number">0</span>;

        <span class="hljs-comment">// Filtrar las mediciones del mes y año que se desea promediar</span>
        datosFiltrados = datos.filter(<span class="hljs-function"><span class="hljs-params">f</span> =&gt;</span>
            <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>(f.Fecha.toString()).getFullYear() === ano
            &amp;&amp; <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>(f.Fecha.toString()).getMonth() === mes
        );

        <span class="hljs-keyword">if</span> (datosFiltrados.length &gt; <span class="hljs-number">0</span>) {
            <span class="hljs-comment">// Obtener la suma de los valores de las mediciones a promediar</span>
            suma = datosFiltrados.map(<span class="hljs-function"><span class="hljs-params">m</span> =&gt;</span> m.Nivel)
                .reduce(<span class="hljs-function">(<span class="hljs-params">a, b</span>) =&gt;</span> a + b);
            cantidadMediciones = datosFiltrados.length;
            promedio = suma / cantidadMediciones;
        }
        <span class="hljs-keyword">return</span> promedio;
    }
}
</code></pre>
<p>De esta manera, cada vez que los datos del usuario cambien, se ejecutara esta función que procesa los datos para generar un promedio mensual y comparar estos datos con los del año anterior.</p>
<h4 id="heading-el-metodo-sort"><strong>EL MÉTODO SORT()</strong></h4>
<p>En la función setter de “mediciones” ordenamos los objetos en el arreglo “datos” por fecha utilizando el método sort() (línea 51).</p>
<p>El método sort() ordena los elementos de un array de objetos y devuelve el array ordenado de acuerdo al valor que retorna la función de comparación dada. Siendo a y b dos elementos comparados, entonces:</p>
<ol>
<li><p>Si el valor retornado es menor que 0, se sitúa “a” en un índice menor que “b”. Es decir, “a” viene primero.</p>
</li>
<li><p>Si el valor retornado es 0, se deja “a” y “b” sin cambios entre ellos, pero ordenados con respecto a todos los elementos diferentes.</p>
</li>
<li><p>Si el valor retornado es mayor que 0, se sitúa “b” en un índice menor que “a”.</p>
</li>
</ol>
<p>En este caso, la función de comparación regresa el resultado de la resta entre las fechas de diferentes registros de mediciones.</p>
<h4 id="heading-el-metodo-reduce"><strong>EL MÉTODO REDUCE()</strong></h4>
<p>En la función “getPromedioMediciones()” estamos obteniendo la suma de los niveles de glucosa para después calcular el promedio de los niveles recibidos. Para esto, primero utilizamos el método map() para obtener un arreglo de los niveles de glucosa, “[1,2,3,4,5]” y después obtenemos la suma de las mediciones con el método reduce().</p>
<p>El método reduce() ejecuta una función reductora sobre cada elemento de un array, devolviendo como resultado un único valor.</p>
<p>En esta función, utilizamos el método reduce para obtener la suma de todos los elementos sin necesidad de utilizar un ciclo while, for, o el método forEach.</p>
<h3 id="heading-pasar-los-datos-de-la-aplicacion-desde-el-dashboard-al-componente-1"><strong>PASAR LOS DATOS DE LA APLICACIÓN DESDE EL DASHBOARD AL COMPONENTE</strong></h3>
<p>De la misma manera que con el primer componente, necesitamos pasar los registros de la aplicación a través de la propiedad de entrada “mediciones”. Actualiza el archivo “dashboard.component.html”:</p>
<p><img src="https://rckstr1.github.io/images/blog/GLTrack4/12-ComparativoChartInput.png" alt /></p>
<h3 id="heading-actualizar-componente-global-niveles-chart"><strong>ACTUALIZAR COMPONENTE “GLOBAL-NIVELES-CHART”</strong></h3>
<p>Para terminar, actualizaremos el ultimo componente para eliminar datos precargados y crear la propiedad de entrada “mediciones”. Modifica el código del archivo “global-niveles-chart.component.ts”:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> GlobalNivelesChartComponent <span class="hljs-keyword">implements</span> OnInit {
    ...
    <span class="hljs-comment">// public pieChartLabels: Label[] = ['Download Sales', 'In-Store Sales', 'Mail Sales'];</span>
    <span class="hljs-keyword">public</span> pieChartLabels: Label[] = [
        <span class="hljs-string">'Hipoglucemia'</span>, <span class="hljs-string">'Normal'</span>,
        <span class="hljs-string">'Nivel elevado'</span>, <span class="hljs-string">'Altamente elevado'</span>
    ];

    <span class="hljs-comment">// public pieChartData: SingleDataSet = [300, 500, 100];</span>
    <span class="hljs-keyword">public</span> pieChartData: SingleDataSet = [];
    ...
    <span class="hljs-meta">@Input</span>()
    set mediciones(datos: MedicionGlucosa[]) {
        <span class="hljs-keyword">let</span> hipoglucemia = <span class="hljs-number">0</span>;
        <span class="hljs-keyword">let</span> normal = <span class="hljs-number">0</span>;
        <span class="hljs-keyword">let</span> elevado = <span class="hljs-number">0</span>;
        <span class="hljs-keyword">let</span> altamenteElevado = <span class="hljs-number">0</span>;

        datos.forEach(<span class="hljs-function"><span class="hljs-params">m</span> =&gt;</span> {
            <span class="hljs-keyword">if</span> (m.Nivel &lt;= <span class="hljs-number">70</span>) {
                hipoglucemia++;
            } <span class="hljs-keyword">else</span> {
                <span class="hljs-keyword">if</span> (m.Nivel &lt;= <span class="hljs-number">115</span>) {
                    normal++;
                } <span class="hljs-keyword">else</span> {
                    <span class="hljs-keyword">if</span> (m.Nivel &lt;= <span class="hljs-number">180</span>) {
                        elevado++;
                    } <span class="hljs-keyword">else</span> {
                        altamenteElevado++;
                    }
                }
            }
        });
        <span class="hljs-built_in">this</span>.pieChartData = [hipoglucemia, normal, 
            elevado, altamenteElevado];
    }

    <span class="hljs-keyword">constructor</span>(<span class="hljs-params"></span>) { }

    ngOnInit() {
    }
}
</code></pre>
<p><img src="https://rckstr1.github.io/images/blog/GLTrack4/13-GlobalChartCode.png" alt /></p>
<p>Los cambios consisten en lo siguiente:</p>
<ol>
<li><p>Reemplazamos las etiquetas precargadas con las 4 categorías en las que clasificaremos los datos.</p>
</li>
<li><p>Eliminamos los datos precargados en el componente.</p>
</li>
<li><p>Creamos la propiedad de entrada “mediciones” con una función setter que se encarga de clasificar los datos disponibles en las categorías que definimos en el paso 1. Para después, llenar la gráfica con la cantidad de mediciones por categoría.</p>
</li>
</ol>
<p>Para concluir, actualiza el archivo “dashboard.component.html” para pasar los datos de la aplicación a este componente:</p>
<p><a target="_blank" href="https://rckstr1.github.io/images/blog/GLTrack4/14-GlobalChartInput.png"><img src="https://rckstr1.github.io/images/blog/GLTrack4/14-GlobalChartInput.png" alt /></a></p>
<h2 id="heading-conclusion"><strong>CONCLUSIÓN</strong></h2>
<p><a target="_blank" href="https://rckstr1.github.io/images/blog/GLTrack4/15-DashboardReady.png"><img src="https://rckstr1.github.io/images/blog/GLTrack4/15-DashboardReady.png" alt /></a></p>
<p>En este post terminamos de desarrollar GLTrack, una aplicación para registro de mediciones de glucosa en la sangre para pacientes de diabetes, implementando gráficas de Chart.js con el paquete de directivas para angular ng2-charts.</p>
<p>Procesamos la información de niveles de glucosa del usuario para convertirla en datos que pudiéramos representar visualmente en las gráficas utilizando mapeando, filtrando y reduciendo arreglos de objetos con las funciones map(), filter() y reduce().</p>
<p>También creamos propiedades de entrada en los componentes de angular, con el decorador Input() y funciones setter para interceptar cambios en las propiedades de entrada.</p>
<p>De esta manera concluimos el desarrollo del prototipo de GLTrack.</p>
<p>El código fuente completo de la aplicación de ejemplo puedes encontrarlo en GitHub, en <a target="_blank" href="https://github.com/RCKSTR1/GLTrack4">https://github.com/RCKSTR1/GLTrack4</a> o si prefieres, puedes clonar el repositorio directo en <a target="_blank" href="https://github.com/RCKSTR1/GLTrack4.git">https://github.com/RCKSTR1/GLTrack4.git</a></p>
<p>Si tuviste algún problema o duda al seguir los pasos, o si tienes alguna pregunta acerca de este post, contáctame en Twitter, Facebook o LinkedIn.</p>
<p><strong>Es cuánto.</strong></p>
<h2 id="heading-fuentes"><strong>FUENTES</strong></h2>
<ul>
<li><p>Vive con Diabetes. "Tablas de los rangos de los niveles de azúcar en la sangre". <a target="_blank" href="https://www.vivecondiabetes.com/viviendo-con-diabetes/tratamiento-y-cuidados/9203-tablas-de-los-rangos-de-los-niveles-de-az%C3%BAcar-en-la-sangre.html">https://www.vivecondiabetes.com/viviendo-con-diabetes/tratamiento-y-cuidados/9203-tablas-de-los-rangos-de-los-niveles-de-az%C3%BAcar-en-la-sangre.html</a></p>
</li>
<li><p>ng2-charts. "Angular2 directives for Chart.js". <a target="_blank" href="https://valor-software.com/ng2-charts/">https://valor-software.com/ng2-charts/</a></p>
</li>
<li><p>MDN web docs. "<a target="_blank" href="http://Array.prototype.map">Array.prototype.map</a>()". <a target="_blank" href="https://developer.mozilla.org/es/docs/Web/JavaScript/Referencia/Objetos_globales/Array/map">https://developer.mozilla.org/es/docs/Web/JavaScript/Referencia/Objetos_globales/Array/map</a></p>
</li>
<li><p>MDN web docs. "Array.prototype.filter()". <a target="_blank" href="https://developer.mozilla.org/es/docs/Web/JavaScript/Referencia/Objetos_globales/Array/filter">https://developer.mozilla.org/es/docs/Web/JavaScript/Referencia/Objetos_globales/Array/filter</a></p>
</li>
<li><p>MDN web docs. "Array.prototype.reduce()". <a target="_blank" href="https://developer.mozilla.org/es/docs/Web/JavaScript/Referencia/Objetos_globales/Array/reduce">https://developer.mozilla.org/es/docs/Web/JavaScript/Referencia/Objetos_globales/Array/reduce</a></p>
</li>
<li><p>MDN web docs. "Array.prototype.sort()". <a target="_blank" href="https://developer.mozilla.org/es/docs/Web/JavaScript/Referencia/Objetos_globales/Array/sort">https://developer.mozilla.org/es/docs/Web/JavaScript/Referencia/Objetos_globales/Array/sort</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Reutiliza componentes. Interacción entre componentes usando @input() y EventEmmiter<T> con Angular 8]]></title><description><![CDATA[[Publicado el 22 de Agosto, 2019 en rckstr1.github.io]
INTRODUCCIÓN
En el post de hoy haremos una nueva actualización a la aplicación GLTrack, que hemos venido construyendo y que tiene como objetivo servir para registrar y monitorear un registro pers...]]></description><link>https://publicvoid.hashnode.dev/reutiliza-componentes-interaccion-entre-componentes-usando-input-y-eventemmitert-con-angular-8</link><guid isPermaLink="true">https://publicvoid.hashnode.dev/reutiliza-componentes-interaccion-entre-componentes-usando-input-y-eventemmitert-con-angular-8</guid><category><![CDATA[Angular]]></category><category><![CDATA[material ui]]></category><dc:creator><![CDATA[Adrian Gonzalez]]></dc:creator><pubDate>Sun, 02 Apr 2023 01:51:59 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1680399952717/7358eab9-c087-40cf-a3ec-0f697f8e23d8.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><a target="_blank" href="https://rckstr1.github.io/2019/08/22/GLTrack3.html">[Publicado el 22 de Agosto, 2019 en rckstr1.github.io]</a></p>
<h2 id="heading-introduccion"><strong>INTRODUCCIÓN</strong></h2>
<p>En el post de hoy haremos una nueva actualización a la aplicación GLTrack, que hemos venido construyendo y que tiene como objetivo servir para registrar y monitorear un registro personal de niveles de azúcar en la sangre para pacientes de diabetes.</p>
<p>Me han comentado que los posts anteriores pueden ser demasiado largos y no tan fáciles de entender. Voy a tratar de mantener los posts más breves y al mismo tiempo explicarlos mejor. Aunque creo que este post tampoco quedó tan corto, espero que si esté más claro.</p>
<h4 id="heading-nota-esta-es-la-parte-3-de-4-de-la-serie-de-posts-gltrack"><strong>NOTA: ESTA ES LA PARTE 3 DE 4 DE LA SERIE DE POSTS "GLTRACK"</strong></h4>
<ul>
<li><p><a target="_blank" href="https://rckstr1.github.io/2019/06/18/GLTrack1.html">GLTrack parte 1: "Schematics, Componentes y Ruteo con Angular + Material".</a></p>
</li>
<li><p><a target="_blank" href="https://rckstr1.github.io/2019/08/07/GLTrack2.html">GLTrack parte 2: "Modelos, servicios, dependency injection, formas y data binding con Angular + Material".</a></p>
</li>
<li><p><a target="_blank" href="https://rckstr1.github.io/2019/08/22/GLTrack3.html">GLTrack parte 3: "Reutiliza componentes. Interacción entre componentes usando @Input() y EventEmmiter con Angular 8".</a></p>
</li>
<li><p><a target="_blank" href="https://rckstr1.github.io/2019/09/06/GLTrack4.html">GLTrack parte 4: "Gráficas con ng2-charts (Chart.js) y Angular 8. Ordena, filtra, mapea y reduce arreglos de objetos.".</a></p>
</li>
</ul>
<p>En el post anterior, creamos un formulario para registrar mediciones e implementamos una tabla para mostrar las capturas.</p>
<p>Imagina que GLTrack ya está siendo usado por un usuario final, Diana. Diana entra a la aplicación y registra sus niveles de glucosa. Las mediciones se muestran en la tabla en la página de registro. Pero la aplicación sería mucho más útil para Diana si le mostrara sus datos de una manera más útil.</p>
<p>Hoy comenzaremos a modificar el Dashboard, la página principal de la aplicación. Lo primero que haremos es agregar al dashboard una tabla igual a la que tenemos en la página de registro.</p>
<h2 id="heading-paso-1-crear-nuevo-componente"><strong>PASO 1: CREAR NUEVO COMPONENTE</strong></h2>
<p>La manera incorrecta de agregar la tabla de registro a la página principal sería copiar el código de la tabla de la página de registro y pegarlo en el componente Dashboard. En cambio, lo que vamos a hacer es crear un componente reutilizable que podamos utilizar en la página de registro y en el dashboard sin tener código duplicado en la aplicación.</p>
<p>Comenzaremos creando un componente nuevo desde la consola:</p>
<pre><code class="lang-bash">ng generate component components/tabla-registros
</code></pre>
<p>Ahora, inserta el nuevo componente en la página de registro:</p>
<pre><code class="lang-xml">
<span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Niveles de glucosa<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">mat-card</span>&gt;</span>
    ...
<span class="hljs-tag">&lt;/<span class="hljs-name">mat-card</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">mat-card</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">mat-card-title</span>&gt;</span>Mis registros<span class="hljs-tag">&lt;/<span class="hljs-name">mat-card-title</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">app-tabla-registros</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">app-tabla-registros</span>&gt;</span>
    ...
<span class="hljs-tag">&lt;/<span class="hljs-name">mat-card</span>&gt;</span>
</code></pre>
<p><img src="https://rckstr1.github.io/images/blog/GLTrack3/01-NuevoComponent.png" alt /></p>
<h2 id="heading-paso-2-mover-y-adecuar-el-codigo-de-la-tabla-en-el-nuevo-componente"><strong>PASO 2: MOVER Y ADECUAR EL CÓDIGO DE LA TABLA EN EL NUEVO COMPONENTE</strong></h2>
<h3 id="heading-codigo-html"><strong>CÓDIGO HTML</strong></h3>
<p>Comenzamos moviendo el código HTML de la tabla desde "registro.component.html" hacia "tabla-registros.component.html".</p>
<p>registro.component.html:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Niveles de glucosa<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">mat-card</span>&gt;</span>
    ...
<span class="hljs-tag">&lt;/<span class="hljs-name">mat-card</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">mat-card</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">mat-card-title</span>&gt;</span>Mis registros<span class="hljs-tag">&lt;/<span class="hljs-name">mat-card-title</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">app-tabla-registros</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">app-tabla-registros</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">!-</span> <span class="hljs-attr">El</span> <span class="hljs-attr">codigo</span> <span class="hljs-attr">estaba</span> <span class="hljs-attr">aqui</span> <span class="hljs-attr">-</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">mat-card</span>&gt;</span>
</code></pre>
<p>tabla-registros.component.html:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"row"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">mat-form-field</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"row-item grow"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">matInput</span> (<span class="hljs-attr">keyup</span>)=<span class="hljs-string">"applyFilter($event.target.value)"</span> <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Buscar"</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">mat-form-field</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">table</span> <span class="hljs-attr">mat-table</span> [<span class="hljs-attr">dataSource</span>]=<span class="hljs-string">"dataSource"</span> <span class="hljs-attr">matSort</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">ng-container</span> <span class="hljs-attr">matColumnDef</span>=<span class="hljs-string">"fecha"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">th</span> <span class="hljs-attr">mat-header-cell</span> *<span class="hljs-attr">matHeaderCellDef</span> <span class="hljs-attr">mat-sort-header</span>&gt;</span> Fecha <span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">td</span> <span class="hljs-attr">mat-cell</span> *<span class="hljs-attr">matCellDef</span>=<span class="hljs-string">"let row"</span>&gt;</span> {row.Fecha|date:'medium'} <span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">ng-container</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">ng-container</span> <span class="hljs-attr">matColumnDef</span>=<span class="hljs-string">"nivel"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">th</span> <span class="hljs-attr">mat-header-cell</span> *<span class="hljs-attr">matHeaderCellDef</span> <span class="hljs-attr">mat-sort-header</span>&gt;</span> ID <span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">td</span> <span class="hljs-attr">mat-cell</span> *<span class="hljs-attr">matCellDef</span>=<span class="hljs-string">"let row"</span>&gt;</span> {row.Nivel} <span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">ng-container</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">ng-container</span> <span class="hljs-attr">matColumnDef</span>=<span class="hljs-string">"comida"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">th</span> <span class="hljs-attr">mat-header-cell</span> *<span class="hljs-attr">matHeaderCellDef</span> <span class="hljs-attr">mat-sort-header</span>&gt;</span> Comida <span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">td</span> <span class="hljs-attr">mat-cell</span> *<span class="hljs-attr">matCellDef</span>=<span class="hljs-string">"let row"</span>&gt;</span> {row.Comida} <span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">ng-container</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">ng-container</span> <span class="hljs-attr">matColumnDef</span>=<span class="hljs-string">"antesDespues"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">th</span> <span class="hljs-attr">mat-header-cell</span> *<span class="hljs-attr">matHeaderCellDef</span> <span class="hljs-attr">mat-sort-header</span>&gt;</span> Antes/Después <span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">td</span> <span class="hljs-attr">mat-cell</span> *<span class="hljs-attr">matCellDef</span>=<span class="hljs-string">"let row"</span>&gt;</span> {row.AntesDespues} <span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">ng-container</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">ng-container</span> <span class="hljs-attr">matColumnDef</span>=<span class="hljs-string">"actions"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">th</span> <span class="hljs-attr">mat-header-cell</span> *<span class="hljs-attr">matHeaderCellDef</span>&gt;</span> <span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">td</span> <span class="hljs-attr">mat-cell</span> *<span class="hljs-attr">matCellDef</span>=<span class="hljs-string">"let row"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">mat-icon-button</span> (<span class="hljs-attr">click</span>)=<span class="hljs-string">"Eliminar(row.Id)"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">mat-icon</span>&gt;</span>delete<span class="hljs-tag">&lt;/<span class="hljs-name">mat-icon</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">ng-container</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">tr</span> <span class="hljs-attr">mat-header-row</span> *<span class="hljs-attr">matHeaderRowDef</span>=<span class="hljs-string">"displayedColumns"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">tr</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">tr</span> <span class="hljs-attr">mat-row</span> *<span class="hljs-attr">matRowDef</span>=<span class="hljs-string">"let row; columns: displayedColumns;"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">tr</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">table</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">mat-paginator</span> [<span class="hljs-attr">pageSizeOptions</span>]=<span class="hljs-string">"[5, 10, 25, 100]"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">mat-paginator</span>&gt;</span>
</code></pre>
<h3 id="heading-codigo-typescript"><strong>CÓDIGO TYPESCRIPT</strong></h3>
<p>Ahora continuamos moviendo el código de la tabla desde el archivo registro.component.ts hacia tabla-registros.component.ts. Para más claridad, a continuación, se muestra el código comentado en registro.component.ts:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { Component, OnInit, ViewChild } <span class="hljs-keyword">from</span> <span class="hljs-string">'@angular/core'</span>;
<span class="hljs-keyword">import</span> { MatTableDataSource, MatPaginator, MatSort } <span class="hljs-keyword">from</span> <span class="hljs-string">'@angular/material'</span>;
<span class="hljs-keyword">import</span> { MedicionGlucosa } <span class="hljs-keyword">from</span> <span class="hljs-string">'src/app/models/models'</span>;
<span class="hljs-keyword">import</span> { MedicionesService } <span class="hljs-keyword">from</span> <span class="hljs-string">'src/app/services/mediciones.service'</span>;

<span class="hljs-meta">@Component</span>({
    selector: <span class="hljs-string">'app-registro'</span>,
    templateUrl: <span class="hljs-string">'./registro.component.html'</span>,
    styleUrls: [<span class="hljs-string">'./registro.component.css'</span>]
})
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> RegistroComponent <span class="hljs-keyword">implements</span> OnInit {
    registros = [] <span class="hljs-keyword">as</span> MedicionGlucosa[];
    nuevoRegistro = {} <span class="hljs-keyword">as</span> MedicionGlucosa;

    <span class="hljs-comment">// displayedColumns: string[] = ['fecha', 'nivel', 'comida', 'antesDespues', 'actions'];</span>
    <span class="hljs-comment">// dataSource: MatTableDataSource&lt;MedicionGlucosa&gt;;</span>

    <span class="hljs-comment">// @ViewChild(MatPaginator, { static: true }) paginator: MatPaginator;</span>
    <span class="hljs-comment">// @ViewChild(MatSort, { static: true }) sort: MatSort;</span>

    <span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">private</span> mediciones: MedicionesService</span>) {
    }

    ngOnInit() {
        <span class="hljs-built_in">this</span>.registros = <span class="hljs-built_in">this</span>.mediciones.GetAll();
        <span class="hljs-comment">// this.dataSource = new MatTableDataSource(this.registros);</span>
        <span class="hljs-comment">// this.dataSource.paginator = this.paginator;</span>
        <span class="hljs-comment">// this.dataSource.sort = this.sort;</span>
    }

    Guardar() {
        <span class="hljs-keyword">if</span> (!<span class="hljs-built_in">this</span>.IsInvalid()) {
            <span class="hljs-built_in">this</span>.mediciones.Create(<span class="hljs-built_in">this</span>.nuevoRegistro);
            <span class="hljs-built_in">this</span>.LimpiarForma();
            <span class="hljs-built_in">this</span>.registros = <span class="hljs-built_in">this</span>.mediciones.GetAll();
            <span class="hljs-comment">// this.dataSource.data = this.registros;</span>
        }
    }

    Eliminar(id: <span class="hljs-built_in">string</span>) {
        <span class="hljs-built_in">this</span>.mediciones.Delete(id);
        <span class="hljs-built_in">this</span>.registros = <span class="hljs-built_in">this</span>.mediciones.GetAll();
        <span class="hljs-comment">// this.dataSource.data = this.registros;</span>
    }

    LimpiarForma() {
        <span class="hljs-built_in">this</span>.nuevoRegistro = {} <span class="hljs-keyword">as</span> MedicionGlucosa;
    }

    IsInvalid() {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.nuevoRegistro.Nivel === <span class="hljs-literal">undefined</span>
        || <span class="hljs-built_in">this</span>.nuevoRegistro.Comida === <span class="hljs-literal">undefined</span>
        || <span class="hljs-built_in">this</span>.nuevoRegistro.AntesDespues === <span class="hljs-literal">undefined</span>
        || <span class="hljs-built_in">this</span>.nuevoRegistro.Comida === <span class="hljs-literal">undefined</span>
        || <span class="hljs-built_in">this</span>.nuevoRegistro.Fecha === <span class="hljs-literal">undefined</span>;
    }

    <span class="hljs-comment">// applyFilter(filterValue: string) {</span>
        <span class="hljs-comment">// this.dataSource.filter = filterValue.trim().toLowerCase();</span>

        <span class="hljs-comment">// if (this.dataSource.paginator) {</span>
            <span class="hljs-comment">// this.dataSource.paginator.firstPage();</span>
        <span class="hljs-comment">// }</span>
    <span class="hljs-comment">// }</span>
}
</code></pre>
<p>Puedes eliminar las líneas comentadas una vez que las pegas en "tabla-registros.component.ts":</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { Component, OnInit, ViewChild } <span class="hljs-keyword">from</span> <span class="hljs-string">'@angular/core'</span>;
<span class="hljs-keyword">import</span> { MedicionGlucosa } <span class="hljs-keyword">from</span> <span class="hljs-string">'src/app/models/models'</span>;
<span class="hljs-keyword">import</span> { MatTableDataSource, MatPaginator, MatSort } <span class="hljs-keyword">from</span> <span class="hljs-string">'@angular/material'</span>;

<span class="hljs-meta">@Component</span>({
    selector: <span class="hljs-string">'app-tabla-registros'</span>,
    templateUrl: <span class="hljs-string">'./tabla-registros.component.html'</span>,
    styleUrls: [<span class="hljs-string">'./tabla-registros.component.css'</span>]
})
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> TablaRegistrosComponent <span class="hljs-keyword">implements</span> OnInit {
    registros = [] <span class="hljs-keyword">as</span> MedicionGlucosa[];
    displayedColumns: <span class="hljs-built_in">string</span>[] = [<span class="hljs-string">'fecha'</span>, <span class="hljs-string">'nivel'</span>, <span class="hljs-string">'comida'</span>, <span class="hljs-string">'antesDespues'</span>, <span class="hljs-string">'actions'</span>];
    dataSource: MatTableDataSource&lt;MedicionGlucosa&gt;;

    <span class="hljs-meta">@ViewChild</span>(MatPaginator, { <span class="hljs-keyword">static</span>: <span class="hljs-literal">true</span> }) paginator: MatPaginator;
    <span class="hljs-meta">@ViewChild</span>(MatSort, { <span class="hljs-keyword">static</span>: <span class="hljs-literal">true</span> }) sort: MatSort;

    <span class="hljs-keyword">constructor</span>(<span class="hljs-params"></span>) {
        <span class="hljs-built_in">this</span>.dataSource = <span class="hljs-keyword">new</span> MatTableDataSource(<span class="hljs-built_in">this</span>.registros);
        <span class="hljs-built_in">this</span>.dataSource.paginator = <span class="hljs-built_in">this</span>.paginator;
        <span class="hljs-built_in">this</span>.dataSource.sort = <span class="hljs-built_in">this</span>.sort;
    }

    ngOnInit() {
    }

    applyFilter(filterValue: <span class="hljs-built_in">string</span>) {
        <span class="hljs-built_in">this</span>.dataSource.filter = filterValue.trim().toLowerCase();
        <span class="hljs-keyword">if</span> (<span class="hljs-built_in">this</span>.dataSource.paginator) {
            <span class="hljs-built_in">this</span>.dataSource.paginator.firstPage();
        }
    }
}
</code></pre>
<p>Ahora el componente “tabla-registros.component” se muestra correctamente, pero la tabla aparece vacía, aunque tengamos registros capturados. Esto es porque, aunque la tabla tiene todos los elementos para almacenar y mostrar datos, no tenemos manera de comunicarnos con el componente para enviar o recibir datos.</p>
<h2 id="heading-paso-3-pasar-datos-al-componente-utilizando-input"><strong>PASO 3: PASAR DATOS AL COMPONENTE UTILIZANDO @INPUT()</strong></h2>
<p>Para pasar datos de un componente a otro, en este caso, desde el componente “registro” hacia “tabla-registros” necesitamos agregar una propiedad al componente con el decorador @Input().</p>
<p>Modifica la propiedad “registros” e inserta el siguiente código en tabla-registros.component.ts:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// registros = [] as MedicionGlucosa[];</span>
_registros = [] <span class="hljs-keyword">as</span> MedicionGlucosa[];

<span class="hljs-meta">@Input</span>()
set registros(value: MedicionGlucosa[]) {
    <span class="hljs-built_in">this</span>._registros = value;
    <span class="hljs-built_in">this</span>.dataSource.data = <span class="hljs-built_in">this</span>._registros;
}
</code></pre>
<p>Lo primero que hacemos es cambiar el nombre del arreglo de mediciones en la tabla de “registros” a “_registros”. Esto es porque estamos agregando una nueva propiedad con el nombre “registros”. El decorador @Input() indica que el valor de esta propiedad puede asignarse desde otro componente. La manera más sencilla de utilizar @Input() es la siguiente:</p>
<pre><code class="lang-typescript"><span class="hljs-meta">@Input</span>() registros: MedicionGlucosa[] = [];
</code></pre>
<p>Sin embargo, en este caso necesitamos ejecutar algunas operaciones cuando el valor de la propiedad “registros” cambia:</p>
<ol>
<li><p>Primero, tomamos el valor recibido “value” y lo guardamos en el arreglo “_registros”.</p>
</li>
<li><p>Actualiza la fuente de datos de la tabla de angular material (mat-table).</p>
</li>
</ol>
<p><img src="https://rckstr1.github.io/images/blog/GLTrack3/02-Input.png" alt /></p>
<p>Ahora que tenemos una forma de recibir datos, agrega el siguiente atributo al componente “tabla-registros” en "registro.component.html":</p>
<p><img src="https://rckstr1.github.io/images/blog/GLTrack3/03-PassDataToInput.png" alt /></p>
<p>De esta manera, estamos indicando que el contenido de la propiedad “registros” del componente “registro.component” va a insertarse a la propiedad de entrada “[registros]” del componente “tabla-registros”.</p>
<p>Ahora podemos observar que la tabla que ahora existe dentro del componente “tabla-registros” está mostrando los datos que recibe desde el componente “registro”.</p>
<p><img src="https://rckstr1.github.io/images/blog/GLTrack3/04-DataInputWorks.png" alt /></p>
<h2 id="heading-paso-4-escuchar-eventos-de-un-componente-utilizando-eventemmiterlttgt"><strong>PASO 4: ESCUCHAR EVENTOS DE UN COMPONENTE UTILIZANDO EVENTEMMITER&lt;T&gt;</strong></h2>
<p>Aunque el componente “tabla-registros” puede recibir datos. Al hacer click en el botón para eliminar un registro, podemos observar que, en lugar de eliminar el registro, la consola del navegador arroja un error:</p>
<p><img src="https://rckstr1.github.io/images/blog/GLTrack3/05-Error.png" alt /></p>
<p>Esto sucede porque el botón eliminar intenta ejecutar la función “Eliminar()” cuando el usuario hace click y esta función no existe todavía en el componente:</p>
<p><img src="https://rckstr1.github.io/images/blog/GLTrack3/06-Eliminar.png" alt /></p>
<p>Para solucionar esto, crea la función “Eliminar()” en tabla-registros.component.ts agregando el siguiente código:</p>
<p>Primero estamos creando una propiedad de tipo EventEmmiter&lt;string&gt; y decorándola con “@Output()”. Después, en la función “Eliminar()” estamos recibiendo como parámetro el Id del registro a eliminar y emitiendo el evento “itemDeleted” con el Id recibido.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> TablaRegistrosComponent <span class="hljs-keyword">implements</span> OnInit {
    ...
    <span class="hljs-meta">@Output</span>() itemDeleted = <span class="hljs-keyword">new</span> EventEmitter&lt;<span class="hljs-built_in">string</span>&gt;();
    ...
    Eliminar(id: <span class="hljs-built_in">string</span>) {
        <span class="hljs-built_in">this</span>.itemDeleted.emit(id);
    }
}
</code></pre>
<p>Anteriormente, el código para eliminar un registro estaba dentro de la función Eliminar, sin embargo, el componente “tabla-registros” tiene como única responsabilidad mostrar datos en la pantalla y notificar a otros componentes acerca de las interacciones del usuario, por ejemplo, cuando el usuario hace click en el botón eliminar.</p>
<h3 id="heading-output"><strong>@OUTPUT()</strong></h3>
<p>El decorador “@Output()” indica que podemos leer el valor de la propiedad desde otro componente, de una manera muy similar a como lo hacemos con el decorador “@Input()”.</p>
<h3 id="heading-eventemmiterlttgt"><strong>EVENTEMMITER&lt;T&gt;</strong></h3>
<p>EventEmmiter es una clase incluida en Angular que se usa en propiedades con el decorador “@Output()” para emitir eventos personalizados a los que podemos suscribirnos. “&lt;T&gt;” indica que al crear un EventEmmiter podemos configurar el tipo de dato que va a incluir el evento. En este caso estamos configurando el evento para contener un string.</p>
<p><img src="https://rckstr1.github.io/images/blog/GLTrack3/07-EventEmmiter.png" alt /></p>
<p><img src="https://rckstr1.github.io/images/blog/GLTrack3/08-ListenToOutput.png" alt /></p>
<p>Ahora que tenemos listo el EventEmmiter, podemos suscribirnos al evento itemDeleted para ejecutar alguna función cuando sea invocado. Agrega el siguiente atributo a “app-tabla-registros” en registro.component.html:</p>
<p>De esta manera, el componente “registro.component” queda suscrito al evento, y cuando el usuario haga click en el botón eliminar, el componente “tabla-registros” dispara el evento “itemDeleted” y entonces el componente “registro.component” ejecuta la función “Eliminar()”.</p>
<p><img src="https://rckstr1.github.io/images/blog/GLTrack3/09-EventChain.png" alt /></p>
<ol>
<li><p>Cuando el usuario hace click en el botón para eliminar un registro, el componente “tabla-registros” ejecuta la función “Eliminar()”.</p>
</li>
<li><p>La función “Eliminar()” en “tabla-registros.component.ts” emite el evento “itemDeleted” que contiene el Id del registro a eliminar.</p>
</li>
<li><p>El componente “registro.component” está suscrito al evento, y cuando el evento se emite, ejecuta la función “Eliminar()” pasando como parámetro el Id del registro a eliminar.</p>
</li>
<li><p>La función “Eliminar()” en “registro.component.ts” se encarga de recibir el Id del registro a eliminar y llama al servicio encargado del almacenamiento de datos para que sea eliminado.</p>
</li>
</ol>
<h2 id="heading-paso-5-reutilizar-el-componente-tabla-registros"><strong>PASO 5: REUTILIZAR EL COMPONENTE “TABLA-REGISTROS”</strong></h2>
<p>Ahora que tenemos un componente independiente y reutilizable, podemos insertar la tabla de registros en la página principal de la aplicación. Agrega el componente al dashboard con el siguiente código en dashboard.component.html:</p>
<pre><code class="lang-xml">...
<span class="hljs-tag">&lt;<span class="hljs-name">mat-card</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">app-tabla-registros</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">app-tabla-registros</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">mat-card</span>&gt;</span>
</code></pre>
<p>La tabla se muestra correctamente, pero de nuevo nos encontramos con que no tiene datos para mostrar. Esto es porque el componente “tabla-registros” necesita recibir los datos a través del atributo de entrada “[registros]”.</p>
<p>Ahora debemos actualizar “dashboard.component.ts” para que recupere los datos y los pase a la tabla:</p>
<pre><code class="lang-typescript">...
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> DashboardComponent <span class="hljs-keyword">implements</span> OnInit {
registros = [] <span class="hljs-keyword">as</span> MedicionGlucosa[];

    <span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">private</span> mediciones: MedicionesService</span>) {
    }

    ngOnInit() {
        <span class="hljs-built_in">this</span>.registros = <span class="hljs-built_in">this</span>.mediciones.GetAll();
    }
}
</code></pre>
<p>Ahora el componente tiene una propiedad “registros” que contiene los registros capturados por el usuario.</p>
<p>Utilizando Dependency Injection de Angular, en el constructor se está inyectando el servicio “MedicionesService” que se encarga de leer y escribir los registros de mediciones. De esta manera, Angular se encarga de que una instancia del servicio esté disponible en el componente.</p>
<p>Después, en la función “ngOnInit()” indicamos que una vez que el componente se cargue, recupere los registros de mediciones y los guarde en la propiedad “registros”.</p>
<p>Por último, necesitamos pasar los registros al componente “tabla-registros” utilizando el atributo de entrada “[registros]”. Actualiza “dashboard.component.html”:</p>
<p>Ahora la tabla de registros está disponible también en la página principal reutilizando el componente “tabla-registros” sin la necesidad de tener código duplicado. De esta manera la aplicación es más fácil de actualizar y mantener.</p>
<p><img src="https://rckstr1.github.io/images/blog/GLTrack3/10-DashboardTableCode.png" alt /></p>
<h3 id="heading-nuevo-problema"><strong>NUEVO PROBLEMA</strong></h3>
<p><img src="https://rckstr1.github.io/images/blog/GLTrack3/11-DashboardTableView.png" alt /></p>
<p>Ahora tenemos un nuevo problema. Supongamos que, por seguridad, el usuario debe poder eliminar capturas de mediciones desde la página de registro, pero no desde la página principal de la aplicación.</p>
<p>Necesitamos actualizar el componente “tabla-registros” para que podamos configurar si los botones para eliminar registros están disponibles en ciertos casos.</p>
<p>Para esto, necesitamos hacer algunas modificaciones en “tabla-registros.component.ts”:</p>
<pre><code class="lang-typescript">...
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> TablaRegistrosComponent <span class="hljs-keyword">implements</span> OnInit {
    …
    <span class="hljs-meta">@Input</span>() permitirEliminar = <span class="hljs-literal">true</span>;
    …
    <span class="hljs-comment">// displayedColumns: string[] = ['fecha', 'nivel', 'comida', 'antesDespues', 'actions'];</span>
    …
    GetDisplayerColumns() {
        <span class="hljs-keyword">const</span> displayedColumns: <span class="hljs-built_in">string</span>[] = [<span class="hljs-string">'fecha'</span>, <span class="hljs-string">'nivel'</span>, <span class="hljs-string">'comida'</span>, <span class="hljs-string">'antesDespues'</span>];
        <span class="hljs-keyword">if</span> (<span class="hljs-built_in">this</span>.permitirEliminar) {
            displayedColumns.push(<span class="hljs-string">'actions'</span>);
        }

        <span class="hljs-keyword">return</span> displayedColumns;
    }
}
</code></pre>
<p>Estas modificaciones consisten en lo siguiente:</p>
<ol>
<li><p>Agregamos una nueva propiedad de entrada “permitirEliminar”, con un valor verdadero (“true”) por default.</p>
</li>
<li><p>Eliminamos la propiedad “displayedColumns” que guardaba un arreglo con los nombres de las columnas que se muestran en la tabla.</p>
</li>
<li><p>Creamos una función nueva “GetDisplayedColumns()” que tiene como valor de retorno un arreglo con los nombres de las columnas que se mostrarán en la tabla. Esta función evalúa el valor de la propiedad “permitirEliminar” y si es verdadero entonces agrega la columna “actions” que es la que contiene el botón para eliminar registros.</p>
</li>
</ol>
<p>Ahora necesitamos actualizar “tabla-registros.component.html” para que lea la lista de columnas desde la función “GetDisplayedColumns()” que acabamos de crear:</p>
<p><a target="_blank" href="https://rckstr1.github.io/images/blog/GLTrack3/12-GetDisplayedColumns().png"><img src="https://rckstr1.github.io/images/blog/GLTrack3/12-GetDisplayedColumns().png" alt /></a></p>
<p>De esta manera, el componente “tabla-registros” muestra los botones para eliminar por default, pero ahora podemos configurarlo para ocultarlos si es necesario.</p>
<p>Para ocultar los botones en la pantalla principal de la aplicación, agrega el atributo de entrada “permitirEliminar” en “dashboard.component.html”:</p>
<p><a target="_blank" href="https://rckstr1.github.io/images/blog/GLTrack3/13-PermitirEliminar.png"><img src="https://rckstr1.github.io/images/blog/GLTrack3/13-PermitirEliminar.png" alt /></a></p>
<p>De esta manera, evitamos que la tabla muestre los botones para eliminar registros en el dashboard de la aplicación.</p>
<p><a target="_blank" href="https://rckstr1.github.io/images/blog/GLTrack3/14-NoDeleteButton.png"><img src="https://rckstr1.github.io/images/blog/GLTrack3/14-NoDeleteButton.png" alt /></a></p>
<h2 id="heading-conclusion"><strong>CONCLUSIÓN</strong></h2>
<p>En este post continuamos construyendo GLTrack, una aplicación para registro de mediciones de glucosa en la sangre para pacientes de diabetes.</p>
<p>Para evitar tener código duplicado en la aplicación, creamos un componente reutilizable para mostrar la tabla de registros en la página principal y en la página de registros de la aplicación.</p>
<p>Utilizamos los decoradores “@Input()” y “@Output()” así como EventEmmiter&lt;T&gt; para interactuar entre componentes de angular y pasar datos de entrada y salida.</p>
<p>También reutilizamos servicios de angular en diferentes componentes con Dependency Injection de Angular 8.</p>
<p>En el siguiente post, continuaremos trabajando en el Dashboard de la aplicación, para mostrar datos relevantes para el usuario acerca de sus mediciones de glucosa a través de graficas que muestren los datos capturados en la aplicación de manera visual.</p>
<p>El código fuente completo de la aplicación de ejemplo puedes encontrarlo en GitHub, en <a target="_blank" href="https://github.com/RCKSTR1/GLTrack3">https://github.com/RCKSTR1/GLTrack3</a> o si prefieres, puedes clonar el repositorio directo en <a target="_blank" href="https://github.com/RCKSTR1/GLTrack3.git">https://github.com/RCKSTR1/GLTrack3.git</a></p>
<p>Si tuviste algún problema o duda al seguir los pasos, o si tienes alguna pregunta acerca de este post, contáctame en Twitter, Facebook o LinkedIn.</p>
<p><strong>Es cuánto.</strong></p>
<h2 id="heading-fuentes"><strong>FUENTES</strong></h2>
<ul>
<li><p>Documentación de Angular. "Propiedades de @Input() y @Output()". <a target="_blank" href="https://angular.io/guide/template-syntax#input-and-output-properties">https://angular.io/guide/template-syntax#input-and-output-properties</a></p>
</li>
<li><p>Documentación de Angular. "EventEmitter". <a target="_blank" href="https://angular.io/api/core/EventEmitter#eventemitter">https://angular.io/api/core/EventEmitter#eventemitter</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Modelos, servicios, dependency injection, formas y data binding con Angular + Material]]></title><description><![CDATA[[Publicado el 7 de Agosto, 2019 en rckstr1.github.io]
INTRODUCCIÓN
Hola de nuevo, hace tiempo que no escribía, estuve ocupado trabajando en un proyecto con Angular y ASP.NET Core, aprendí mucho y planeo compartir algunas cosas en próximos posts.
En e...]]></description><link>https://publicvoid.hashnode.dev/modelos-servicios-dependency-injection-formas-y-data-binding-con-angular-material</link><guid isPermaLink="true">https://publicvoid.hashnode.dev/modelos-servicios-dependency-injection-formas-y-data-binding-con-angular-material</guid><category><![CDATA[Angular]]></category><category><![CDATA[material ui]]></category><dc:creator><![CDATA[Adrian Gonzalez]]></dc:creator><pubDate>Sun, 02 Apr 2023 01:44:01 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1680399267931/756e1922-7c3b-4a31-bcfc-b6196641757e.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><a target="_blank" href="https://rckstr1.github.io/2019/08/07/GLTrack2.html">[Publicado el 7 de Agosto, 2019 en rckstr1.github.io]</a></p>
<h2 id="heading-introduccion"><strong>INTRODUCCIÓN</strong></h2>
<p>Hola de nuevo, hace tiempo que no escribía, estuve ocupado trabajando en un proyecto con Angular y <a target="_blank" href="http://ASP.NET">ASP.NET</a> Core, aprendí mucho y planeo compartir algunas cosas en próximos posts.</p>
<p>En este post continuaremos trabajando en GLTrack, nuestra aplicación para registrar y monitorear un registro personal de niveles de azúcar en la sangre, esas mediciones que deben tomarse regularmente los pacientes de diabetes.</p>
<blockquote>
<p><em>En el post anterior, habíamos creado una aplicación con tres componentes básicos: navegación, dashboard y registro. Eso ya hace 1 mes y medio, así que si necesitas refrescar la memoria aquí está el link.</em> <a target="_blank" href="https://rckstr1.github.io/2019/06/18/GLTrack1.html"><em>"Schematics, Componentes y Ruteo con Angular + Material"</em></a><em>.</em></p>
</blockquote>
<p>Hoy continuaremos trabajando en el componente de registro, este componente va a permitir que el usuario registre sus niveles de glucosa y que pueda revisar y eliminar registros si es necesario.</p>
<h4 id="heading-nota-esta-es-la-parte-2-de-4-de-la-serie-de-posts-gltrack"><strong>NOTA: ESTA ES LA PARTE 2 DE 4 DE LA SERIE DE POSTS "GLTRACK"</strong></h4>
<ul>
<li><p><a target="_blank" href="https://rckstr1.github.io/2019/06/18/GLTrack1.html">GLTrack parte 1: "Schematics, Componentes y Ruteo con Angular + Material".</a></p>
</li>
<li><p><a target="_blank" href="https://rckstr1.github.io/2019/08/07/GLTrack2.html">GLTrack parte 2: "Modelos, servicios, dependency injection, formas y data binding con Angular + Material".</a></p>
</li>
<li><p><a target="_blank" href="https://rckstr1.github.io/2019/08/22/GLTrack3.html">GLTrack parte 3: "Reutiliza componentes. Interacción entre componentes usando @Input() y EventEmmiter con Angular 8".</a></p>
</li>
<li><p><a target="_blank" href="https://rckstr1.github.io/2019/09/06/GLTrack4.html">GLTrack parte 4: "Gráficas con ng2-charts (Chart.js) y Angular 8. Ordena, filtra, mapea y reduce arreglos de objetos.".</a></p>
</li>
</ul>
<h2 id="heading-paso-1-disenar-un-modelo-de-datos"><strong>PASO 1: DISEÑAR UN MODELO DE DATOS</strong></h2>
<p>Como primer paso debemos diseñar un modelo que defina los datos que vamos a guardar. Para esto necesitamos crear una clase o interfaz que contenga las propiedades que necesitamos. En el archivo models.ts crearemos la siguiente interfaz:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">interface</span> MedicionGlucosa {
    Id: <span class="hljs-built_in">string</span>;
    Timestamp: <span class="hljs-built_in">Date</span>;
    Nivel: <span class="hljs-built_in">number</span>;
    Comida: <span class="hljs-built_in">string</span>;
    AntesDespues: <span class="hljs-built_in">string</span>;
    Fecha: <span class="hljs-built_in">Date</span>;
}
</code></pre>
<h2 id="heading-paso-2-crear-una-forma-de-captura"><strong>PASO 2: CREAR UNA FORMA DE CAPTURA</strong></h2>
<p>Comenzaremos creando un objeto nuevo para capturar una nueva medición agregando esta línea en el componente registro.component.ts:</p>
<pre><code class="lang-typescript">nuevoRegistro = {} <span class="hljs-keyword">as</span> MedicionGlucosa;
</code></pre>
<p>Antes de continuar con la interfaz gráfica, necesitamos importar algunos módulos de material para poder usar componentes como select y datepicker de angular material. Importa y exporta los siguientes módulos en material.module.ts:</p>
<pre><code class="lang-typescript">FormsModule,
MatSelectModule,
MatDatepickerModule,
MatNativeDateModule
</code></pre>
<p>Una vez importados los módulos necesarios podemos agregar los controles para el formulario en registro.component.html:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Niveles de glucosa<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">mat-card</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">mat-card-title</span>&gt;</span>Nuevo registro<span class="hljs-tag">&lt;/<span class="hljs-name">mat-card-title</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"row"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">mat-form-field</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"row-item grow"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">matInput</span> <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Nivel de glucosa"</span> [(<span class="hljs-attr">ngModel</span>)]=<span class="hljs-string">"nuevoRegistro.Nivel"</span> <span class="hljs-attr">required</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">mat-form-field</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">mat-form-field</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"row-item grow"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">mat-label</span>&gt;</span>Comida<span class="hljs-tag">&lt;/<span class="hljs-name">mat-label</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">mat-select</span> [(<span class="hljs-attr">ngModel</span>)]=<span class="hljs-string">"nuevoRegistro.Comida"</span> <span class="hljs-attr">required</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">mat-option</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"Desayuno"</span>&gt;</span>Desayuno<span class="hljs-tag">&lt;/<span class="hljs-name">mat-option</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">mat-option</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"Comida"</span>&gt;</span>Comida<span class="hljs-tag">&lt;/<span class="hljs-name">mat-option</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">mat-option</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"Cena"</span>&gt;</span>Cena<span class="hljs-tag">&lt;/<span class="hljs-name">mat-option</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">mat-select</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">mat-form-field</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">mat-form-field</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"row-item grow"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">mat-label</span>&gt;</span>Antes o después de alimentos<span class="hljs-tag">&lt;/<span class="hljs-name">mat-label</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">mat-select</span> [(<span class="hljs-attr">ngModel</span>)]=<span class="hljs-string">"nuevoRegistro.AntesDespues"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">mat-option</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"Antes"</span>&gt;</span>Antes<span class="hljs-tag">&lt;/<span class="hljs-name">mat-option</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">mat-option</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"Despues"</span>&gt;</span>Después<span class="hljs-tag">&lt;/<span class="hljs-name">mat-option</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">mat-select</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">mat-form-field</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">mat-form-field</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"row-item grow"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">matInput</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"datetime-local"</span> <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Fecha"</span> [(<span class="hljs-attr">ngModel</span>)]=<span class="hljs-string">"nuevoRegistro.Fecha"</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">mat-form-field</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"row-item"</span> <span class="hljs-attr">mat-button</span> [<span class="hljs-attr">disabled</span>]=<span class="hljs-string">"IsInvalid()"</span> (<span class="hljs-attr">click</span>)=<span class="hljs-string">"Guardar()"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">mat-icon</span>&gt;</span>save<span class="hljs-tag">&lt;/<span class="hljs-name">mat-icon</span>&gt;</span> Guardar
        <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"row-item"</span> <span class="hljs-attr">mat-button</span> (<span class="hljs-attr">click</span>)=<span class="hljs-string">"LimpiarForma()"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">mat-icon</span>&gt;</span>delete<span class="hljs-tag">&lt;/<span class="hljs-name">mat-icon</span>&gt;</span> Cancelar
        <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">mat-card</span>&gt;</span>
</code></pre>
<p>Como puedes observar, los controles como input y mat-select tienen un atributo [(ngModel)], en este atributo estamos especificando una variable o propiedad de un objeto con el que va a estar ligado el control. Por ejemplo, el control “Nivel de glucosa” estará ligado a la propiedad “Nivel” del objeto “nuevoRegistro” que acabamos de crear en registro.component.ts.</p>
<p><img src="https://rckstr1.github.io/images/blog/GLTrack2/01-Binding.png" alt /></p>
<p>Observa que el atributo ngModel está envuelto en corchetes “[]” y paréntesis “()”, esto indica que la sincronización del valor es en dos sentidos, entrada “[]” y salida “()”. De esta manera, el valor del control en HTML queda sincronizado con el valor del objeto en nuestro componente.</p>
<p><img src="https://rckstr1.github.io/images/blog/GLTrack2/02-Buttons.png" alt /></p>
<p>También podemos ver que los botones del formulario tienen los atributos [disabled] y (click). Esto indica que solamente nos interesa escribir el valor de “[disabled]” con el resultado de la función “IsInvalid()” y que solamente estaremos escuchando el evento “(click)” de los botones.</p>
<h3 id="heading-el-boton-guardar"><strong>EL BOTÓN “GUARDAR”</strong></h3>
<p>En este caso, el valor de “[disabled]” va a depender del resultado de la función “IsInvalid()”. Agrega esta función en registro.component.ts:</p>
<p>Esta función regresará un valor booleano. Verdadero si alguna de las propiedades del nuevo registro es undefined y falso si todas las propiedades tienen un valor asignado. De esta manera nos aseguramos de que el usuario pueda guardar un registro solamente si ha llenado todos los campos del formulario.</p>
<pre><code class="lang-typescript">IsInvalid() {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.nuevoRegistro.Nivel === <span class="hljs-literal">undefined</span>
        || <span class="hljs-built_in">this</span>.nuevoRegistro.Comida === <span class="hljs-literal">undefined</span>
        || <span class="hljs-built_in">this</span>.nuevoRegistro.AntesDespues === <span class="hljs-literal">undefined</span>
        || <span class="hljs-built_in">this</span>.nuevoRegistro.Comida === <span class="hljs-literal">undefined</span>
        || <span class="hljs-built_in">this</span>.nuevoRegistro.Fecha === <span class="hljs-literal">undefined</span>;
}
</code></pre>
<p>En el botón “Guardar”, indicamos que el evento “(click)” va a ejecutar la función “Guardar()”. Esta función debe encargarse de tomar los datos capturados y enviarlos a una base de datos, un archivo o alguna manera de almacenamiento de datos. En este caso estaremos utilizando “localStorage”, un espacio de almacenamiento del navegador. Agrega las siguientes funciones en registro.component.ts:</p>
<pre><code class="lang-typescript">Guardar() {
    <span class="hljs-built_in">this</span>.nuevoRegistro.Id = <span class="hljs-built_in">this</span>.NewGuid();
    <span class="hljs-keyword">const</span> mediciones = <span class="hljs-built_in">this</span>.GetAll();
    mediciones.push(<span class="hljs-built_in">this</span>.nuevoRegistro);
    <span class="hljs-built_in">localStorage</span>.setItem(<span class="hljs-string">'registros'</span>, <span class="hljs-built_in">JSON</span>.stringify(mediciones));
}

<span class="hljs-keyword">private</span> NewGuid() {
    <span class="hljs-keyword">return</span> <span class="hljs-string">'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'</span>.replace(<span class="hljs-regexp">/[xy]/g</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">c</span>) </span>{
        <span class="hljs-keyword">var</span> r = <span class="hljs-built_in">Math</span>.random() * <span class="hljs-number">16</span> | <span class="hljs-number">0</span>,
        v = c == <span class="hljs-string">'x'</span> ? r : (r &amp; <span class="hljs-number">0x3</span> | <span class="hljs-number">0x8</span>);
        <span class="hljs-keyword">return</span> v.toString(<span class="hljs-number">16</span>);
    });
}
</code></pre>
<p>La función “Guardar()” se está encargando de convertir el nuevo registro en una cadena de caracteres con formato JSON y guardarla en localStorage, mientras que utiliza la función “NewGuid()” para generar un GUID que es usado como llave o identificador único para el nuevo registro.</p>
<p>Esto podría funcionar, sin embargo, la única responsabilidad de este componente debería ser presentar datos en la pantalla y encargarse de las interacciones del usuario con la interfaz gráfica.</p>
<p>Para solucionar esto y cumplir con el 1er principio SOLID – Single responsibility – necesitamos crear un servicio de angular, que se va a encargar del almacenamiento de datos únicamente, sin depender de la interfaz gráfica, de validaciones ni del estado de ningún componente.</p>
<p>En la consola ejecuta el siguiente comando para crear el servicio:</p>
<pre><code class="lang-bash">ng generate service services/mediciones
</code></pre>
<p>Esto creará un nuevo servicio en app/services/mediciones.service.ts.</p>
<p><img src="https://rckstr1.github.io/images/blog/GLTrack2/03-StorageKey.png" alt /></p>
<p>Comenzamos creando una variable que contiene el nombre de la llave que utilizaremos para acceder a los datos guardados en localStorage. De esta manera solo tenemos que modificar este valor si decidimos cambiar el nombre de nuestros datos en localStorage.</p>
<p>El servicio debe encargarse de inicializar nuestros datos en localStorage si es que no existen, por ejemplo, si es la primera vez que ejecutamos la aplicación o si hemos borrado los datos del navegador. Para esto, debemos agregar esta validación al constructor del servicio.</p>
<p><a target="_blank" href="https://rckstr1.github.io/images/blog/GLTrack2/04-ServiceConstructor.png"><img src="https://rckstr1.github.io/images/blog/GLTrack2/04-ServiceConstructor.png" alt /></a></p>
<p>De esta manera cuando el servicio es instanciado en la aplicación, el constructor verifica si existen datos en el navegador y de no ser así inicializa con un arreglo vacío.</p>
<p>Para encargarse de la lectura y escritura de datos, vamos a agregar 3 funciones al servicio: GetAll() para recuperar la lista completa de registros, Create() para guardar un nuevo registro y Delete() para eliminar un registro en especial.</p>
<p><em>Esta función recupera los datos de localStorage como un string y lo convierte en un arreglo de objetos de tipo MedicionGlucosa.</em></p>
<p>Después, agregaremos la función Create(). Esta función recibe como parámetro un objeto que debemos guardar. Para esto, el primer paso es generar una nueva llave única para identificarlo en la lista de objetos. Después, obtenemos la lista de objetos guardados y agregamos el nuevo registro para guardar la lista actualizada.</p>
<p>Observa que la creación de un GUID se encuentra en una función separada “NewGuid()” esta función tiene el modificador “private”, esto quiere decir que esta función solo es accesible dentro del servicio, a diferencia de las demás funciones que son visibles desde otros servicios, módulos o componentes.</p>
<p><img src="https://rckstr1.github.io/images/blog/GLTrack2/06-Create.png" alt /></p>
<p><img src="https://rckstr1.github.io/images/blog/GLTrack2/07-Delete.png" alt /></p>
<p>Por último, agregaremos la función “Delete()” que se encarga de eliminar registros de la lista. Esta función recibe como parámetro un string que debe contener el ID del objeto que será eliminado.</p>
<p>Después de este paso el servicio mediciones.service.ts debe contener lo siguiente:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { Injectable } <span class="hljs-keyword">from</span> <span class="hljs-string">'@angular/core'</span>;
<span class="hljs-keyword">import</span> { MedicionGlucosa } <span class="hljs-keyword">from</span> <span class="hljs-string">'../models/models'</span>;

<span class="hljs-meta">@Injectable</span>({
    providedIn: <span class="hljs-string">'root'</span>
})
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> MedicionesService {
    storageKey = <span class="hljs-string">'mediciones'</span>;

    <span class="hljs-keyword">constructor</span>(<span class="hljs-params"></span>) {
        <span class="hljs-keyword">if</span> (<span class="hljs-built_in">localStorage</span>.getItem(<span class="hljs-built_in">this</span>.storageKey) === <span class="hljs-literal">null</span>) {
            <span class="hljs-built_in">localStorage</span>.setItem(<span class="hljs-built_in">this</span>.storageKey, <span class="hljs-built_in">JSON</span>.stringify([] <span class="hljs-keyword">as</span> MedicionGlucosa[]));
        }
    }

    GetAll() {
        <span class="hljs-keyword">const</span> medicionesString = <span class="hljs-built_in">localStorage</span>.getItem(<span class="hljs-built_in">this</span>.storageKey);
        <span class="hljs-keyword">return</span> <span class="hljs-built_in">JSON</span>.parse(medicionesString) <span class="hljs-keyword">as</span> MedicionGlucosa[];
    }

    Create(mc: MedicionGlucosa) {
        mc.Id = <span class="hljs-built_in">this</span>.NewGuid();

        <span class="hljs-keyword">const</span> mediciones = <span class="hljs-built_in">this</span>.GetAll();
        mediciones.push(mc);
        <span class="hljs-built_in">localStorage</span>.setItem(<span class="hljs-built_in">this</span>.storageKey, <span class="hljs-built_in">JSON</span>.stringify(mediciones));
    }

    Delete(id: <span class="hljs-built_in">string</span>) {
        <span class="hljs-keyword">const</span> mediciones = <span class="hljs-built_in">this</span>.GetAll();
        <span class="hljs-keyword">const</span> i = mediciones.findIndex(<span class="hljs-function"><span class="hljs-params">f</span> =&gt;</span> f.Id === id);
        <span class="hljs-keyword">if</span> (i &gt; <span class="hljs-number">-1</span>) {
            mediciones.splice(i, <span class="hljs-number">1</span>);
            <span class="hljs-built_in">localStorage</span>.setItem(<span class="hljs-built_in">this</span>.storageKey, <span class="hljs-built_in">JSON</span>.stringify(mediciones));
        }
    }

    <span class="hljs-keyword">private</span> NewGuid() {
        <span class="hljs-keyword">return</span> <span class="hljs-string">'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'</span>.replace(<span class="hljs-regexp">/[xy]/g</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">c</span>) </span>{
            <span class="hljs-keyword">var</span> r = <span class="hljs-built_in">Math</span>.random() * <span class="hljs-number">16</span> | <span class="hljs-number">0</span>,
            v = c == <span class="hljs-string">'x'</span> ? r : (r &amp; <span class="hljs-number">0x3</span> | <span class="hljs-number">0x8</span>);
            <span class="hljs-keyword">return</span> v.toString(<span class="hljs-number">16</span>);
        });
    }
}
</code></pre>
<p>Ahora podemos regresar al componente de registro y actualizarlo para dejar que el servicio se encargue de leer y escribir los datos.</p>
<p>Para poder utilizar el servicio que acabamos de crear desde registro.component.ts necesitamos utilizar una técnica conocida como Dependency Injection. De esta manera, no necesitamos crear una instancia del servicio, sino que Angular se encargará de crearla e inyectarla en todos los componentes que la necesiten. Para utilizar Dependency Injection, solamente agrega un parámetro al constructor del componente en registro.component.ts:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { MedicionesService } <span class="hljs-keyword">from</span> <span class="hljs-string">'src/app/services/mediciones.service'</span>;
…
<span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">private</span> mediciones: MedicionesService</span>) {
}
</code></pre>
<p>Esto es suficiente para que una instancia del servicio “MedicionesService” sea accesible desde el componente.</p>
<p>Ahora podemos actualizar la función “Guardar()” en registro.component.ts para que solo se encargue de actualizar la interfaz gráfica y le deje el trabajo de escribir los datos al servicio inyectado:</p>
<pre><code class="lang-typescript">Guardar() {
    <span class="hljs-keyword">if</span> (!<span class="hljs-built_in">this</span>.IsInvalid()) {
        <span class="hljs-built_in">this</span>.mediciones.Create(<span class="hljs-built_in">this</span>.nuevoRegistro);
        <span class="hljs-built_in">this</span>.LimpiarForma();
        <span class="hljs-built_in">this</span>.registros = <span class="hljs-built_in">this</span>.mediciones.GetAll();
        <span class="hljs-built_in">this</span>.dataSource.data = <span class="hljs-built_in">this</span>.registros;
    }
}

LimpiarForma() {
    <span class="hljs-built_in">this</span>.nuevoRegistro = {} <span class="hljs-keyword">as</span> MedicionGlucosa;
}
</code></pre>
<p>Además de actualizar la función “Guardar()” hemos creado una función “LimpiarForma()” que se encarga de limpiar los controles del formulario reinicializando el objeto “nuevoRegistro”. Recuerda que los controles del formulario están ligados a este objeto utilizando la directiva “ngModel”, por eso no es necesario manipular el HTML manualmente.</p>
<p>Esta función (“LimpiarForma()”) también es utilizada por el botón “Cancelar” del formulario.</p>
<h2 id="heading-paso-3-crear-tabla-de-registros"><strong>PASO 3: CREAR TABLA DE REGISTROS</strong></h2>
<p>A continuación, necesitamos crear un componente que muestre una tabla con los datos guardados por el usuario.</p>
<p><a target="_blank" href="https://rckstr1.github.io/images/blog/GLTrack2/08-Tabla.png"><img src="https://rckstr1.github.io/images/blog/GLTrack2/08-Tabla.png" alt /></a></p>
<p>Agrega el siguiente código HTML al archivo registro.component.html:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">mat-card</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">mat-card-title</span>&gt;</span>Mis registros<span class="hljs-tag">&lt;/<span class="hljs-name">mat-card-title</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"row"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">mat-form-field</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"row-item grow"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">matInput</span> (<span class="hljs-attr">keyup</span>)=<span class="hljs-string">"applyFilter($event.target.value)"</span> <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Buscar"</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">mat-form-field</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">table</span> <span class="hljs-attr">mat-table</span> [<span class="hljs-attr">dataSource</span>]=<span class="hljs-string">"dataSource"</span> <span class="hljs-attr">matSort</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">ng-container</span> <span class="hljs-attr">matColumnDef</span>=<span class="hljs-string">"fecha"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">th</span> <span class="hljs-attr">mat-header-cell</span> *<span class="hljs-attr">matHeaderCellDef</span> <span class="hljs-attr">mat-sort-header</span>&gt;</span> Fecha <span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">td</span> <span class="hljs-attr">mat-cell</span> *<span class="hljs-attr">matCellDef</span>=<span class="hljs-string">"let row"</span>&gt;</span> {{row.Fecha|date:'medium'}} <span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">ng-container</span>&gt;</span>

            <span class="hljs-tag">&lt;<span class="hljs-name">ng-container</span> <span class="hljs-attr">matColumnDef</span>=<span class="hljs-string">"nivel"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">th</span> <span class="hljs-attr">mat-header-cell</span> *<span class="hljs-attr">matHeaderCellDef</span> <span class="hljs-attr">mat-sort-header</span>&gt;</span> ID <span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">td</span> <span class="hljs-attr">mat-cell</span> *<span class="hljs-attr">matCellDef</span>=<span class="hljs-string">"let row"</span>&gt;</span> {{row.Nivel}} <span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">ng-container</span>&gt;</span>

            <span class="hljs-tag">&lt;<span class="hljs-name">ng-container</span> <span class="hljs-attr">matColumnDef</span>=<span class="hljs-string">"comida"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">th</span> <span class="hljs-attr">mat-header-cell</span> *<span class="hljs-attr">matHeaderCellDef</span> <span class="hljs-attr">mat-sort-header</span>&gt;</span> Comida <span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">td</span> <span class="hljs-attr">mat-cell</span> *<span class="hljs-attr">matCellDef</span>=<span class="hljs-string">"let row"</span>&gt;</span> {{row.Comida}} <span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">ng-container</span>&gt;</span>

            <span class="hljs-tag">&lt;<span class="hljs-name">ng-container</span> <span class="hljs-attr">matColumnDef</span>=<span class="hljs-string">"antesDespues"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">th</span> <span class="hljs-attr">mat-header-cell</span> *<span class="hljs-attr">matHeaderCellDef</span> <span class="hljs-attr">mat-sort-header</span>&gt;</span> Antes/Después <span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">td</span> <span class="hljs-attr">mat-cell</span> *<span class="hljs-attr">matCellDef</span>=<span class="hljs-string">"let row"</span>&gt;</span> {{row.AntesDespues}} <span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">ng-container</span>&gt;</span>

            <span class="hljs-tag">&lt;<span class="hljs-name">ng-container</span> <span class="hljs-attr">matColumnDef</span>=<span class="hljs-string">"actions"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">th</span> <span class="hljs-attr">mat-header-cell</span> *<span class="hljs-attr">matHeaderCellDef</span>&gt;</span> <span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">td</span> <span class="hljs-attr">mat-cell</span> *<span class="hljs-attr">matCellDef</span>=<span class="hljs-string">"let row"</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">mat-icon-button</span> (<span class="hljs-attr">click</span>)=<span class="hljs-string">"Eliminar(row.Id)"</span>&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">mat-icon</span>&gt;</span>delete<span class="hljs-tag">&lt;/<span class="hljs-name">mat-icon</span>&gt;</span>
                    <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">ng-container</span>&gt;</span>

            <span class="hljs-tag">&lt;<span class="hljs-name">tr</span> <span class="hljs-attr">mat-header-row</span> *<span class="hljs-attr">matHeaderRowDef</span>=<span class="hljs-string">"displayedColumns"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">tr</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">tr</span> <span class="hljs-attr">mat-row</span> *<span class="hljs-attr">matRowDef</span>=<span class="hljs-string">"let row; columns: displayedColumns;"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">tr</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">table</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">mat-paginator</span> [<span class="hljs-attr">pageSizeOptions</span>]=<span class="hljs-string">"[5, 10, 25, 100]"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">mat-paginator</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">mat-card</span>&gt;</span>
</code></pre>
<p>Además de definir aspectos estéticos del componente, estamos insertando un campo de texto para filtrar los contenidos de la tabla, también especifica las columnas disponibles y el dato que mostraremos en cada una de ellas. Por último, estamos insertando un paginador para ayudar al usuario a navegar entre sus registros.</p>
<p>Ahora necesitamos conectar los datos en registro.component.ts a la tabla. Para esto comenzaremos creando una variable que guardará la lista de registros en el componente.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> RegistroComponent <span class="hljs-keyword">implements</span> OnInit {
    registros = [] <span class="hljs-keyword">as</span> MedicionGlucosa[];
    nuevoRegistro = {} <span class="hljs-keyword">as</span> MedicionGlucosa;
    …
}
</code></pre>
<p>También debemos agregar algunas variables para el funcionamiento de la tabla:</p>
<pre><code class="lang-typescript">displayedColumns: <span class="hljs-built_in">string</span>[] = [<span class="hljs-string">'fecha'</span>, <span class="hljs-string">'nivel'</span>, <span class="hljs-string">'comida'</span>, <span class="hljs-string">'antesDespues'</span>, <span class="hljs-string">'actions'</span>];
dataSource: MatTableDataSource&lt;MedicionGlucosa&gt;;

<span class="hljs-meta">@ViewChild</span>(MatPaginator, { <span class="hljs-keyword">static</span>: <span class="hljs-literal">true</span> }) paginator: MatPaginator;
<span class="hljs-meta">@ViewChild</span>(MatSort, { <span class="hljs-keyword">static</span>: <span class="hljs-literal">true</span> }) sort: MatSort;
</code></pre>
<p>La variable “displayedColumns” es un arreglo de strings que indica el nombre de las columnas y el orden en el que serán mostradas en la tabla, estos valores deben coincidir con el nombre que hemos indicado en el archivo registro.component.html.</p>
<p><a target="_blank" href="https://rckstr1.github.io/images/blog/GLTrack2/09-Columnas.png"><img src="https://rckstr1.github.io/images/blog/GLTrack2/09-Columnas.png" alt /></a></p>
<p>Ahora tenemos una tabla lista para mostrar datos, pero necesitamos recuperar los datos existentes para llenar la tabla cuando se carga el componente. Para esto necesitamos utilizar el servicio mediciones.service.ts en la función “ngOnInit()” de nuestro componente. Agrega las siguientes líneas en el archivo registro.component.ts:</p>
<pre><code class="lang-typescript">ngOnInit() {
    <span class="hljs-built_in">this</span>.registros = <span class="hljs-built_in">this</span>.mediciones.GetAll();
    <span class="hljs-built_in">this</span>.dataSource = <span class="hljs-keyword">new</span> MatTableDataSource(<span class="hljs-built_in">this</span>.registros);
    <span class="hljs-built_in">this</span>.dataSource.paginator = <span class="hljs-built_in">this</span>.paginator;
    <span class="hljs-built_in">this</span>.dataSource.sort = <span class="hljs-built_in">this</span>.sort;
}
</code></pre>
<p>De esta manera, cuando se inicializa registro.component.ts recuperamos los datos almacenados e inicializamos la tabla para mostrar los datos.</p>
<p>Lo único que falta en la tabla es la habilidad de eliminar un registro. Para esto utilizaremos el botón en la última columna.</p>
<p><a target="_blank" href="https://rckstr1.github.io/images/blog/GLTrack2/10-Delete.png"><img src="https://rckstr1.github.io/images/blog/GLTrack2/10-Delete.png" alt /></a></p>
<p>Esta columna muestra un botón para eliminar registros. Con el atributo (click) estaremos ejecutando la función “Eliminar()” cuando el usuario dispare el evento “click”. Agrega la función “Eliminar()” en registro.component.ts:</p>
<pre><code class="lang-typescript">
Eliminar(id: <span class="hljs-built_in">string</span>) {
    <span class="hljs-built_in">this</span>.mediciones.Delete(id);
    <span class="hljs-built_in">this</span>.registros = <span class="hljs-built_in">this</span>.mediciones.GetAll();
    <span class="hljs-built_in">this</span>.dataSource.data = <span class="hljs-built_in">this</span>.registros;
}
</code></pre>
<p>Esta función recibe como parámetro el id del registro a eliminar y utiliza el servicio mediciones.service.ts para llevar a cabo la operación. Después de eliminar el registro, vuelve a utilizar el servicio para obtener los datos actualizados y actualiza los datos de la tabla.</p>
<p>Después de este paso, registro.component.ts queda así:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { Component, OnInit, ViewChild } <span class="hljs-keyword">from</span> <span class="hljs-string">'@angular/core'</span>;
<span class="hljs-keyword">import</span> { MatTableDataSource, MatPaginator, MatSort } <span class="hljs-keyword">from</span> <span class="hljs-string">'@angular/material'</span>;
<span class="hljs-keyword">import</span> { MedicionGlucosa } <span class="hljs-keyword">from</span> <span class="hljs-string">'src/app/models/models'</span>;
<span class="hljs-keyword">import</span> { MedicionesService } <span class="hljs-keyword">from</span> <span class="hljs-string">'src/app/services/mediciones.service'</span>;

<span class="hljs-meta">@Component</span>({
    selector: <span class="hljs-string">'app-registro'</span>,
    templateUrl: <span class="hljs-string">'./registro.component.html'</span>,
    styleUrls: [<span class="hljs-string">'./registro.component.css'</span>]
})
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> RegistroComponent <span class="hljs-keyword">implements</span> OnInit {
    registros = [] <span class="hljs-keyword">as</span> MedicionGlucosa[];
    nuevoRegistro = {} <span class="hljs-keyword">as</span> MedicionGlucosa;

    displayedColumns: <span class="hljs-built_in">string</span>[] = [<span class="hljs-string">'fecha'</span>, <span class="hljs-string">'nivel'</span>, <span class="hljs-string">'comida'</span>, <span class="hljs-string">'antesDespues'</span>, <span class="hljs-string">'actions'</span>];
    dataSource: MatTableDataSource&lt;MedicionGlucosa&gt;;

    <span class="hljs-meta">@ViewChild</span>(MatPaginator, { <span class="hljs-keyword">static</span>: <span class="hljs-literal">true</span> }) paginator: MatPaginator;
    <span class="hljs-meta">@ViewChild</span>(MatSort, { <span class="hljs-keyword">static</span>: <span class="hljs-literal">true</span> }) sort: MatSort;

    <span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">private</span> mediciones: MedicionesService</span>) {
    }

    ngOnInit() {
        <span class="hljs-built_in">this</span>.registros = <span class="hljs-built_in">this</span>.mediciones.GetAll();
        <span class="hljs-built_in">this</span>.dataSource = <span class="hljs-keyword">new</span> MatTableDataSource(<span class="hljs-built_in">this</span>.registros);
        <span class="hljs-built_in">this</span>.dataSource.paginator = <span class="hljs-built_in">this</span>.paginator;
        <span class="hljs-built_in">this</span>.dataSource.sort = <span class="hljs-built_in">this</span>.sort;
    }

    Guardar() {
        <span class="hljs-keyword">if</span> (!<span class="hljs-built_in">this</span>.IsInvalid()) {
            <span class="hljs-built_in">this</span>.mediciones.Create(<span class="hljs-built_in">this</span>.nuevoRegistro);
            <span class="hljs-built_in">this</span>.LimpiarForma();
            <span class="hljs-built_in">this</span>.registros = <span class="hljs-built_in">this</span>.mediciones.GetAll();
            <span class="hljs-built_in">this</span>.dataSource.data = <span class="hljs-built_in">this</span>.registros;
        }
    }

    Eliminar(id: <span class="hljs-built_in">string</span>) {
        <span class="hljs-built_in">this</span>.mediciones.Delete(id);
        <span class="hljs-built_in">this</span>.registros = <span class="hljs-built_in">this</span>.mediciones.GetAll();
        <span class="hljs-built_in">this</span>.dataSource.data = <span class="hljs-built_in">this</span>.registros;
    }

    LimpiarForma() {
        <span class="hljs-built_in">this</span>.nuevoRegistro = {} <span class="hljs-keyword">as</span> MedicionGlucosa;
    }

    IsInvalid() {
        <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.nuevoRegistro.Nivel === <span class="hljs-literal">undefined</span>
        || <span class="hljs-built_in">this</span>.nuevoRegistro.Comida === <span class="hljs-literal">undefined</span>
        || <span class="hljs-built_in">this</span>.nuevoRegistro.AntesDespues === <span class="hljs-literal">undefined</span>
        || <span class="hljs-built_in">this</span>.nuevoRegistro.Comida === <span class="hljs-literal">undefined</span>
        || <span class="hljs-built_in">this</span>.nuevoRegistro.Fecha === <span class="hljs-literal">undefined</span>;
    }

    applyFilter(filterValue: <span class="hljs-built_in">string</span>) {
        <span class="hljs-built_in">this</span>.dataSource.filter = filterValue.trim().toLowerCase();

        <span class="hljs-keyword">if</span> (<span class="hljs-built_in">this</span>.dataSource.paginator) {
            <span class="hljs-built_in">this</span>.dataSource.paginator.firstPage();
        }
    }
}
</code></pre>
<h2 id="heading-conclusion"><strong>CONCLUSIÓN</strong></h2>
<p>En este post continuamos construyendo GLTrack, una aplicación para registro de mediciones de glucosa en la sangre para pacientes de diabetes.</p>
<p>Para construir el componente de registro diseñamos un modelo de datos y creamos un formulario de captura utilizando Template-Driven forms de Angular y data-binding con la directiva ngModel.</p>
<p>También creamos un servicio y lo implementamos con Dependency Injection. Por último, creamos una tabla con filtros, sorting y paginación utilizando el componente MatTable de Angular Material.</p>
<p>En el siguiente post, continuaremos construyendo un Dashboard como página de inicio de la aplicación, donde mostraremos datos relevantes para el usuario acerca de sus mediciones de glucosa implementando valores de entrada y salida para interactuar entre componentes.</p>
<p>El código fuente completo de la aplicación de ejemplo puedes encontrarlo en GitHub, en <a target="_blank" href="https://github.com/RCKSTR1/GLTrack2">https://github.com/RCKSTR1/GLTrack2</a> o si prefieres, puedes clonar el repositorio directo en <a target="_blank" href="https://github.com/RCKSTR1/GLTrack2.git">https://github.com/RCKSTR1/GLTrack2.git</a></p>
<p>Si tuviste algún problema o duda al seguir los pasos, o si tienes alguna pregunta acerca de este post, contáctame en Twitter, Facebook o LinkedIn.</p>
<p><strong>Es cuánto.</strong></p>
<h2 id="heading-fuentes"><strong>FUENTES</strong></h2>
<ul>
<li><p>Documentación de Angular. "Template-driven forms". <a target="_blank" href="https://angular.io/guide/forms">https://angular.io/guide/forms</a></p>
</li>
<li><p>Documentación de Angular. "Introducción a los servicios y dependency injection". <a target="_blank" href="https://angular.io/guide/architecture-services">https://angular.io/guide/architecture-services</a></p>
</li>
<li><p>Documentación de Angular Material, "Form field". <a target="_blank" href="https://material.angular.io/components/form-field/overview">https://material.angular.io/components/form-field/overview</a></p>
</li>
<li><p>Documentación de Angular Material, "Input". <a target="_blank" href="https://material.angular.io/components/input/overview">https://material.angular.io/components/input/overview</a></p>
</li>
<li><p>Documentación de Angular Material, "Select". <a target="_blank" href="https://material.angular.io/components/select/overview">https://material.angular.io/components/select/overview</a></p>
</li>
<li><p>Documentación de Angular Material, "Table". <a target="_blank" href="https://material.angular.io/components/table/overview">https://material.angular.io/components/table/overview</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Schematics, componentes y ruteo con Angular + Material]]></title><description><![CDATA[[Publicado el 18 de Junio, 2019 en rckstr1.github.io]
INTRODUCCIÓN
En este post comenzaremos a crear una aplicación para registrar y monitorear un registro personal de niveles de glucosa en la sangre, esas mediciones que deben tomarse regularmente lo...]]></description><link>https://publicvoid.hashnode.dev/schematics-componentes-y-ruteo-con-angular-material</link><guid isPermaLink="true">https://publicvoid.hashnode.dev/schematics-componentes-y-ruteo-con-angular-material</guid><category><![CDATA[Angular]]></category><category><![CDATA[material ui]]></category><dc:creator><![CDATA[Adrian Gonzalez]]></dc:creator><pubDate>Sun, 02 Apr 2023 00:07:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1680393559076/778f6984-30df-4035-b342-d15ea399efe3.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><a target="_blank" href="https://rckstr1.github.io/2019/06/18/GLTrack1.html">[Publicado el 18 de Junio, 2019 en rckstr1.github.io]</a></p>
<h2 id="heading-introduccion"><strong>INTRODUCCIÓN</strong></h2>
<p>En este post comenzaremos a crear una aplicación para registrar y monitorear un registro personal de niveles de glucosa en la sangre, esas mediciones que deben tomarse regularmente los pacientes de diabetes.</p>
<p>Para crear nuestra aplicación utilizaremos componentes, esquemas prefabricados, gráficas, servicios y ruteo de Angular, así como componentes de Material Design para nuestra interfaz gráfica.</p>
<p>Nuestra aplicación constará de las siguientes características:</p>
<ol>
<li><p>Registro de mediciones de glucosa.</p>
</li>
<li><p>Dashboard de resultados con gráficas.</p>
</li>
</ol>
<h4 id="heading-nota-esta-es-la-parte-1-de-4-de-la-serie-de-posts-gltrack"><strong>NOTA: ESTA ES LA PARTE 1 DE 4 DE LA SERIE DE POSTS "GLTRACK"</strong></h4>
<ul>
<li><p><a target="_blank" href="https://rckstr1.github.io/2019/06/18/GLTrack1.html">GLTrack parte 1: "Schematics, Componentes y Ruteo con Angular + Material".</a></p>
</li>
<li><p><a target="_blank" href="https://rckstr1.github.io/2019/08/07/GLTrack2.html">GLTrack parte 2: "Modelos, servicios, dependency injection, formas y data binding con Angular + Material".</a></p>
</li>
<li><p><a target="_blank" href="https://rckstr1.github.io/2019/08/22/GLTrack3.html">GLTrack parte 3: "Reutiliza componentes. Interacción entre componentes usando @Input() y EventEmmiter con Angular 8".</a></p>
</li>
<li><p><a target="_blank" href="https://rckstr1.github.io/2019/09/06/GLTrack4.html">GLTrack parte 4: "Gráficas con ng2-charts (Chart.js) y Angular 8. Ordena, filtra, mapea y reduce arreglos de objetos.".</a></p>
</li>
</ul>
<h2 id="heading-paso-1-crear-una-nueva-aplicacion-e-instalar-angular-material"><strong>PASO 1: CREAR UNA NUEVA APLICACIÓN E INSTALAR ANGULAR MATERIAL</strong></h2>
<p>Comenzaremos creando una aplicación nueva, instalando Angular Material y preparando una interfaz gráfica básica ejecutando los siguientes comandos en la terminal.</p>
<pre><code class="lang-bash">ng new gltrack-app
ng add @angular/material
</code></pre>
<p><img src="https://rckstr1.github.io/images/blog/GLTrack1/01-AddMaterial.png" alt /></p>
<blockquote>
<p><em>Si necesitas ayuda creando una aplicación de Angular, puedes ver los detalles en el post</em> <a target="_blank" href="https://rckstr1.github.io/2019/05/30/HolaAngular8.html"><em>"¡Hola Angular 8!"</em></a><em>.</em></p>
<p><em>Si necesitas ayuda instalando Angular Material, puedes ver los detalles en el post</em> <a target="_blank" href="https://rckstr1.github.io/2019/06/04/AngularMaterial.html"><em>"Angular + Material"</em></a><em>.</em></p>
</blockquote>
<h2 id="heading-paso-2-crear-menu-de-navegacion-con-schematics-de-angular-material"><strong>PASO 2: CREAR MENÚ DE NAVEGACIÓN CON SCHEMATICS DE ANGULAR MATERIAL</strong></h2>
<p>Angular Material incluye esquemas prefabricados que nos permiten construir nuestras aplicaciones de manera más fácil y rápida.</p>
<p>Esta ocasión crearemos un menú de navegación utilizando el schematic 'navigation' para crear un componente que incluye una barra de herramientas con el nombre de la aplicación y una barra de navegación responsiva. En la terminal, ejecuta el siguiente comando:</p>
<pre><code class="lang-bash">ng generate @angular/material:nav components/nav
</code></pre>
<p><img src="https://rckstr1.github.io/images/blog/GLTrack1/02-NavSchematic.png" alt /></p>
<p>Hay que destacar que al indicar “components/[nombre del nuevo componente]” estamos creando el nuevo componente dentro de una carpeta “components” que va a contener los componentes de nuestra app. Esto nos permite tener nuestro código mejor organizado.</p>
<p>Después de generar nuestro componente de navegación, podemos ver que se importaron los módulos de Angular Material necesarios de manera automática directamente en el archivo app.module.ts.</p>
<p>Como buena práctica, crearemos un módulo separado para encargarse de importar los módulos de Angular Material con el siguiente comando:</p>
<pre><code class="lang-bash">ng generate module modules/material
</code></pre>
<p><img src="https://rckstr1.github.io/images/blog/GLTrack1/03-MaterialModule.png" alt /></p>
<p>Después, hay que mover las referencias a los módulos de Angular Material de app.module.ts a material.module.ts.</p>
<p><img src="https://rckstr1.github.io/images/blog/GLTrack1/04-MoveMaterialModules.png" alt /></p>
<p><img src="https://rckstr1.github.io/images/blog/GLTrack1/05-CustomMaterialModule.png" alt /></p>
<p>Ahora, importa el módulo MaterialModule en app.module.ts.</p>
<p><img src="https://rckstr1.github.io/images/blog/GLTrack1/06-ImportMaterialModule.png" alt /></p>
<h2 id="heading-paso-3-crear-componentes"><strong>PASO 3: CREAR COMPONENTES</strong></h2>
<p>Para crear los componentes necesarios para nuestra aplicación, ejecuta:</p>
<pre><code class="lang-bash">ng generate component components/dashboard
ng generate component components/registro
</code></pre>
<p><img src="https://rckstr1.github.io/images/blog/GLTrack1/07-CreateComponents.png" alt /></p>
<h2 id="heading-paso-4-preparar-navegacion-y-ruteo"><strong>PASO 4: PREPARAR NAVEGACIÓN Y RUTEO</strong></h2>
<p>Después de crear los componentes principales que conforman nuestra app, necesitamos permitir que el usuario pueda navegar entre ellos.</p>
<h3 id="heading-ruteo-de-angular"><strong>RUTEO DE ANGULAR</strong></h3>
<p>Actualiza el contenido de la constante “routes” en el archivo app-routing.module.ts como se muestra a continuación:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> routes: Routes = [
    { <span class="hljs-attr">path</span>: <span class="hljs-string">''</span>, <span class="hljs-attr">redirectTo</span>: <span class="hljs-string">'dashboard'</span>, <span class="hljs-attr">pathMatch</span>: <span class="hljs-string">'full'</span> },
    { <span class="hljs-attr">path</span>: <span class="hljs-string">'404'</span>, <span class="hljs-attr">redirectTo</span>: <span class="hljs-string">'dashboard'</span>, <span class="hljs-attr">pathMatch</span>: <span class="hljs-string">'full'</span> },
    { <span class="hljs-attr">path</span>: <span class="hljs-string">'dashboard'</span>, <span class="hljs-attr">component</span>: DashboardComponent },
    { <span class="hljs-attr">path</span>: <span class="hljs-string">'registro'</span>, <span class="hljs-attr">component</span>: RegistroComponent }
];
</code></pre>
<p><img src="https://rckstr1.github.io/images/blog/GLTrack1/08-Routes.png" alt /></p>
<p>De esta manera, estamos registrando las rutas a las que el usuario puede navegar en nuestra aplicación. En la primera ruta, estamos estableciendo un valor predeterminado para cuando el usuario navegue a la raíz de nuestra app, en este caso, estaríamos redirigiendo a la ruta ‘dashboard’.</p>
<p>En la segunda ruta estamos indicando que cuando el usuario navegue por error a alguna ruta que no exista sea redirigido al dashboard.</p>
<p>En las últimas dos rutas estamos indicando las rutas disponibles y el componente que debe mostrarse en cada ruta.</p>
<p>Una vez creadas las rutas, elimina el contenido auto generado en app.component.html para que quede de la siguiente manera:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">router-outlet</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">router-outlet</span>&gt;</span>
</code></pre>
<p><img src="https://rckstr1.github.io/images/blog/GLTrack1/09-RouterOutlet.png" alt /></p>
<p>Ahora, navega a las diferentes rutas de la app para comprobar el funcionamiento del ruteo de Angular.</p>
<p><img src="https://rckstr1.github.io/images/blog/GLTrack1/10-RouteTest.png" alt /></p>
<h3 id="heading-implementar-el-componente-de-navegacion"><strong>IMPLEMENTAR EL COMPONENTE DE NAVEGACIÓN</strong></h3>
<p>En pasos anteriores creamos un componente de navegación utilizando schematics de Angular Material, para comenzar a utilizar el componente, agrega la siguiente línea al archivo nav.component.html justo al final del bloque “mat-sidenav-content”:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">ng-content</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">ng-content</span>&gt;</span>
</code></pre>
<p>El contenido de nav.component.html debe quedar como se muestra a continuación:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">mat-sidenav-container</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"sidenav-container"</span>&gt;</span>

    ...

    <span class="hljs-tag">&lt;<span class="hljs-name">mat-sidenav-content</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">mat-toolbar</span> <span class="hljs-attr">color</span>=<span class="hljs-string">"primary"</span>&gt;</span>

    ...

    <span class="hljs-tag">&lt;/<span class="hljs-name">mat-toolbar</span>&gt;</span>
    <span class="hljs-comment">&lt;!-- Add Content Here --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">ng-content</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">ng-content</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">mat-sidenav-content</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">mat-sidenav-container</span>&gt;</span>
</code></pre>
<p><img src="https://rckstr1.github.io/images/blog/GLTrack1/11-NgContent.png" alt /></p>
<p>A continuación, reemplaza los contenidos del archivo app.component.html con lo siguiente:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">app-nav</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">router-outlet</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">router-outlet</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">app-nav</span>&gt;</span>
</code></pre>
<p><img src="https://rckstr1.github.io/images/blog/GLTrack1/12-NavComponent.png" alt /></p>
<p>De esta manera, nuestra app muestra el componente de navegación, así como el componente que hayamos indicado en cada una de las rutas registradas para nuestra app en app-routing.module.ts.</p>
<p><a target="_blank" href="https://rckstr1.github.io/images/blog/GLTrack1/13-NavComponentImplementation.png"><img src="https://rckstr1.github.io/images/blog/GLTrack1/13-NavComponentImplementation.png" alt /></a></p>
<h3 id="heading-preparar-menu-de-navegacion"><strong>PREPARAR MENÚ DE NAVEGACIÓN</strong></h3>
<p>Para crear nuestro menú de navegación, en lugar de escribir un menú de opciones estático, comenzaremos creando un arreglo de opciones que, de ser necesario, podríamos modificar de manera dinámica utilizando alguna fuente externa.</p>
<p>Primero, crearemos un nuevo archivo models.ts dentro de un folder nuevo en nuestra app. En el nuevo archivo models.ts, modelaremos una interfaz que usaremos como plantilla para nuestras opciones del menú de navegación:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">interface</span> NavMenuItem {
    Label: <span class="hljs-built_in">string</span>;
    Target: <span class="hljs-built_in">string</span>;
}
</code></pre>
<p><img src="https://rckstr1.github.io/images/blog/GLTrack1/14-MenuItemModel.png" alt /></p>
<p>Ahora, en el componente de navegación nav.component.ts, crea un arreglo con la lista de opciones que mostraremos en nuestro menú de la siguiente manera:</p>
<pre><code class="lang-typescript">...

<span class="hljs-keyword">import</span> { NavMenuItem } <span class="hljs-keyword">from</span> <span class="hljs-string">'src/app/models/models'</span>;

...
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> NavComponent {
    menu = [
        { Label: <span class="hljs-string">'Dashboard'</span>, Target: <span class="hljs-string">'/dashboard'</span> },
        { Label: <span class="hljs-string">'Registro'</span>, Target: <span class="hljs-string">'/registro'</span> }
    ] <span class="hljs-keyword">as</span> NavMenuItem[];

    ...
}
</code></pre>
<p><img src="https://rckstr1.github.io/images/blog/GLTrack1/15-MenuOptionsArray.png" alt /></p>
<p>Después de crear la lista de opciones, actualiza nav.component.html para generar las opciones del menú de navegación de manera dinámica. Elimina las opciones estáticas para incluir lo siguiente:</p>
<pre><code class="lang-xml">...
<span class="hljs-tag">&lt;<span class="hljs-name">mat-toolbar</span>&gt;</span>Menu<span class="hljs-tag">&lt;/<span class="hljs-name">mat-toolbar</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">mat-nav-list</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">mat-list-item</span> *<span class="hljs-attr">ngFor</span>=<span class="hljs-string">"let option of menu"</span>
    [<span class="hljs-attr">routerLink</span>]=<span class="hljs-string">"option.Target"</span>&gt;</span>{{ option.Label }}<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">mat-nav-list</span>&gt;</span>
...
</code></pre>
<p><img src="https://rckstr1.github.io/images/blog/GLTrack1/16-DynamicMenu.png" alt /></p>
<p>De esta manera, se estará generando una opción en el menú por cada objeto en nuestro arreglo de opciones y ahora podemos utilizar el menu para navegar entre las rutas de la aplicación.</p>
<h2 id="heading-conclusion"><strong>CONCLUSIÓN</strong></h2>
<p>En este post vimos los pasos necesarios para generar componentes de Angular 8 en blanco, así como utilizando esquemas prefabricados (schematics). También utilizamos las características básicas del ruteo de Angular.</p>
<p>En la segunda parte de este post, continuaremos agregando funcionalidad a nuestra app implementando modelos de datos, formas de angular y data binding, así como servicios para leer y escribir datos.</p>
<p><a target="_blank" href="https://rckstr1.github.io/images/blog/GLTrack1/17-ItWorks.png"><img src="https://rckstr1.github.io/images/blog/GLTrack1/17-ItWorks.png" alt /></a></p>
<p>El código fuente completo de la aplicación de ejemplo puedes encontrarlo en GitHub, en <a target="_blank" href="https://github.com/RCKSTR1/GLTrack1">https://github.com/RCKSTR1/GLTrack1</a> o si prefieres, puedes clonar el repositorio directo en <a target="_blank" href="https://github.com/RCKSTR1/GLTrack1.git">https://github.com/RCKSTR1/GLTrack1.git</a></p>
<p>Si tuviste algún problema o duda al seguir los pasos, o si tienes alguna pregunta acerca de este post, contáctame en Twitter, Facebook o LinkedIn.</p>
<p><strong>Es cuánto.</strong></p>
<h2 id="heading-fuentes"><strong>FUENTES</strong></h2>
<ul>
<li><p>Documentación de Angular Material, "Schematics". <a target="_blank" href="https://material.angular.io/guide/schematics">https://material.angular.io/guide/schematics</a></p>
</li>
<li><p>Documentación de Angular. "Arquitectura, Introducción a los módulos"<a target="_blank" href="https://angular.io/guide/architecture-modules">https://angular.io/guide/architecture-modules</a></p>
</li>
<li><p>Documentación de Angular, "Fundamentos, Ruteo y navegación" <a target="_blank" href="https://angular.io/guide/router">https://angular.io/guide/router</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Angular + Material]]></title><description><![CDATA[[Publicado el 4 de Junio, 2019 en rckstr1.github.io]
INTRODUCCIÓN
Material Design es un lenguaje visual que sintetiza los principios clásicos de buen diseño con la innovación de tecnología y ciencia. Material Design tiene como objetivo desarrollar un...]]></description><link>https://publicvoid.hashnode.dev/angular-material</link><guid isPermaLink="true">https://publicvoid.hashnode.dev/angular-material</guid><category><![CDATA[Angular]]></category><category><![CDATA[material ui]]></category><dc:creator><![CDATA[Adrian Gonzalez]]></dc:creator><pubDate>Sat, 01 Apr 2023 23:56:42 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1680392666545/90b9a93b-1e7b-48c9-8769-21fcd5c2226a.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><a target="_blank" href="https://rckstr1.github.io/2019/06/04/AngularMaterial.html">[Publicado el 4 de Junio, 2019 en rckstr1.github.io]</a></p>
<h2 id="heading-introduccion"><strong>INTRODUCCIÓN</strong></h2>
<p>Material Design es un lenguaje visual que sintetiza los principios clásicos de buen diseño con la innovación de tecnología y ciencia. Material Design tiene como objetivo desarrollar un sistema que unifique la experiencia de usuario a través de diferentes plataformas, dispositivos y métodos de entrada y al mismo tiempo, proveer una base personalizable y flexible para la innovación.</p>
<p>Angular Material es una librería de componentes para aplicaciones con Angular. Estos componentes nos permiten crear aplicaciones atractivas, consistentes y funcionales apegándose a los principios de Material Design.</p>
<h2 id="heading-paso-1-instalar-angular-material-angular-cdk-y-angular-animations"><strong>PASO 1: INSTALAR ANGULAR MATERIAL, ANGULAR CDK Y ANGULAR ANIMATIONS</strong></h2>
<blockquote>
<p><em>Si necesitas ayuda creando una aplicación de Angular, puedes ver los detalles en el post</em> <a target="_blank" href="https://rckstr1.github.io/2019/05/30/HolaAngular8.html"><em>"¡Hola Angular 8!"</em></a><em>.</em></p>
</blockquote>
<p>Puedes usar NPM o YARN para instalar los paquetes. Desde el folder de tu aplicación, en la terminal del sistema ejecuta la siguiente línea:</p>
<h3 id="heading-npm"><strong>NPM</strong></h3>
<pre><code class="lang-bash">npm install --save @angular/material @angular/cdk @angular/animations
</code></pre>
<h3 id="heading-yarn"><strong>YARN</strong></h3>
<pre><code class="lang-bash">yarn add @angular/material @angular/cdk @angular/animations
</code></pre>
<h2 id="heading-paso-2-configurar-las-animaciones"><strong>PASO 2: CONFIGURAR LAS ANIMACIONES</strong></h2>
<p>Después de instalar el paquete de animaciones, importa el módulo <strong>BrowserAnimationsModule</strong> en tu aplicación para habilitar el soporte de animaciones.</p>
<p>En el archivo app.module.ts de tu aplicación, agrega BrowserAnimationsModule a la lista de imports.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> {BrowserAnimationsModule} <span class="hljs-keyword">from</span> <span class="hljs-string">'@angular/platform-browser/animations'</span>;

<span class="hljs-meta">@NgModule</span>({
    ...
    imports: [BrowserAnimationsModule],
    ...
})
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> AppModule { }
</code></pre>
<p><img src="https://rckstr1.github.io/images/blog/AngularMaterial/01-ImportAnimations.png" alt /></p>
<h2 id="heading-paso-3-importar-los-componentes-de-material-ui"><strong>PASO 3: IMPORTAR LOS COMPONENTES DE MATERIAL UI</strong></h2>
<p>Los componentes de Material pueden importarse directamente en app.module.ts, sin embargo, como buena práctica, vamos a crear un módulo separado para importar los componentes. De esta manera, podemos tener nuestros módulos mejor organizados.</p>
<ol>
<li><p>En la consola, ejecuta la siguiente línea:</p>
</li>
<li><pre><code class="lang-bash"> ng generate module material
</code></pre>
</li>
<li><p>Importa el nuevo módulo en app.module.ts</p>
</li>
<li><p><img src="https://rckstr1.github.io/images/blog/AngularMaterial/02-CustomModule.png" alt /></p>
</li>
<li><p>Importa y exporta los componentes de Material en el módulo material.module.ts</p>
</li>
<li><p>Para este ejemplo importaremos los siguientes componentes:</p>
<ul>
<li><p>MatButtonModule</p>
</li>
<li><p>MatMenuModule</p>
</li>
<li><p>MatToolbarModule</p>
</li>
<li><p>MatIconModule</p>
</li>
<li><p>MatCardModule</p>
</li>
<li><p>MatSidenavModule</p>
</li>
<li><p>MatListModule</p>
</li>
</ul>
</li>
</ol>
<p>    Ya importados los componentes que vamos a utilizar, podemos llamarlos desde nuestra aplicación.</p>
<p>    <img src="https://rckstr1.github.io/images/blog/AngularMaterial/03-ImportComponents.png" alt /></p>
<h3 id="heading-estilos-iconos-y-soporte-de-gestos-opcional"><strong>ESTILOS, ÍCONOS Y SOPORTE DE GESTOS (OPCIONAL)</strong></h3>
<h4 id="heading-temas-prefabricados"><strong>TEMAS PREFABRICADOS</strong></h4>
<p>Podemos incluir estilos prefabricados en nuestra aplicación, para este ejemplo, agrega lo siguiente a styles.css.</p>
<pre><code class="lang-typescript"><span class="hljs-meta">@import</span> <span class="hljs-string">"~@angular/material/prebuilt-themes/deeppurple-amber.css"</span>;
</code></pre>
<h4 id="heading-soporte-de-gestos"><strong>SOPORTE DE GESTOS</strong></h4>
<p>Algunos componentes como slide toggle, sliders y tooltips requieren HammerJS para soportar gestos. En este ejemplo no los estamos importando, pero en caso de que quieras usarlos puedes instalar HammerJS desde la consola ejecutando:</p>
<pre><code class="lang-bash">npm install --save hammerjs
</code></pre>
<p>Después de instalar hammerjs, debes importarlo en el archivo main.ts.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> <span class="hljs-string">'hammerjs'</span>;
</code></pre>
<p><img src="https://rckstr1.github.io/images/blog/AngularMaterial/04-hammerjs.png" alt /></p>
<h4 id="heading-iconos"><strong>ICONOS</strong></h4>
<p>Para poder utilizar los iconos de Material UI, tenemos que cargar la fuente de Material Icons en el bloque <strong>head</strong> del archivo index.html.</p>
<pre><code class="lang-bash">&lt;link href=<span class="hljs-string">"https://fonts.googleapis.com/icon?family=Material+Icons"</span> rel=<span class="hljs-string">"stylesheet"</span>&gt;
</code></pre>
<p><img src="https://rckstr1.github.io/images/blog/AngularMaterial/05-Icons.png" alt /></p>
<h2 id="heading-paso-4-construir-nuestra-interfaz-de-usuario"><strong>PASO 4: CONSTRUIR NUESTRA INTERFAZ DE USUARIO</strong></h2>
<p>En este paso crearemos un ejemplo de interfaz de usuario responsiva utilizando los componentes de Material UI importados en nuestra aplicación.</p>
<p><strong>Reemplaza los contenidos de app.component.ts con el siguiente código:</strong></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { Component, ChangeDetectorRef, OnDestroy } <span class="hljs-keyword">from</span> <span class="hljs-string">'@angular/core'</span>;
<span class="hljs-keyword">import</span> { MediaMatcher } <span class="hljs-keyword">from</span> <span class="hljs-string">'@angular/cdk/layout'</span>;

<span class="hljs-meta">@Component</span>({
    selector: <span class="hljs-string">'app-root'</span>,
    templateUrl: <span class="hljs-string">'./app.component.html'</span>,
    styleUrls: [<span class="hljs-string">'./app.component.css'</span>]
})
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> AppComponent <span class="hljs-keyword">implements</span> OnDestroy {
    title = <span class="hljs-string">'Angular + Material'</span>;
    mobileQuery: MediaQueryList;
    fillerNav = [<span class="hljs-string">'Opción 1'</span>, <span class="hljs-string">'Opción 2'</span>, <span class="hljs-string">'Opción 3'</span>, <span class="hljs-string">'Opción 4'</span>, <span class="hljs-string">'Opción 5'</span>, <span class="hljs-string">'Opción 6'</span>, <span class="hljs-string">'Opción 7'</span>];

    fillerContent = <span class="hljs-built_in">Array</span>.from({ length: <span class="hljs-number">50</span> }, <span class="hljs-function">() =&gt;</span> <span class="hljs-string">'Interfaz gráfica usando componentes de Material UI. RCKSTR1 en GitHub. rckstr1.github.io'</span>);

    <span class="hljs-keyword">private</span> _mobileQueryListener: <span class="hljs-function">() =&gt;</span> <span class="hljs-built_in">void</span>;

    <span class="hljs-keyword">constructor</span>(<span class="hljs-params">changeDetectorRef: ChangeDetectorRef, media: MediaMatcher</span>) {
    <span class="hljs-built_in">this</span>.mobileQuery = media.matchMedia(<span class="hljs-string">'(max-width: 600px)'</span>);
    <span class="hljs-built_in">this</span>._mobileQueryListener = <span class="hljs-function">() =&gt;</span> changeDetectorRef.detectChanges();
    <span class="hljs-built_in">this</span>.mobileQuery.addListener(<span class="hljs-built_in">this</span>._mobileQueryListener);
    }

    ngOnDestroy(): <span class="hljs-built_in">void</span> {
    <span class="hljs-built_in">this</span>.mobileQuery.removeListener(<span class="hljs-built_in">this</span>._mobileQueryListener);
    }
}
</code></pre>
<p><strong>Reemplaza los contenidos de app.component.html con el siguiente código:</strong></p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"app-container"</span> [<span class="hljs-attr">class.app-is-mobile</span>]=<span class="hljs-string">"mobileQuery.matches"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">mat-toolbar</span> <span class="hljs-attr">color</span>=<span class="hljs-string">"primary"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"app-toolbar"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">mat-icon-button</span> (<span class="hljs-attr">click</span>)=<span class="hljs-string">"snav.toggle()"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">mat-icon</span>&gt;</span>menu<span class="hljs-tag">&lt;/<span class="hljs-name">mat-icon</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"app-app-name"</span>&gt;</span>{{title}}<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">mat-toolbar</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">mat-sidenav-container</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"app-sidenav-container"</span> [<span class="hljs-attr">style.marginTop.px</span>]=<span class="hljs-string">"mobileQuery.matches ? 56 : 0"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">mat-sidenav</span> #<span class="hljs-attr">snav</span> [<span class="hljs-attr">mode</span>]=<span class="hljs-string">"mobileQuery.matches ? 'over' : 'side'"</span> [<span class="hljs-attr">fixedInViewport</span>]=<span class="hljs-string">"mobileQuery.matches"</span>
        <span class="hljs-attr">fixedTopGap</span>=<span class="hljs-string">"56"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">mat-nav-list</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">mat-list-item</span> <span class="hljs-attr">routerLink</span>=<span class="hljs-string">"."</span> *<span class="hljs-attr">ngFor</span>=<span class="hljs-string">"let nav of fillerNav"</span>&gt;</span>{{nav}}<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">mat-nav-list</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">mat-sidenav</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">mat-sidenav-content</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">router-outlet</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">router-outlet</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span> *<span class="hljs-attr">ngFor</span>=<span class="hljs-string">"let content of fillerContent"</span>&gt;</span>{{content}}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">mat-sidenav-content</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">mat-sidenav-container</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p><strong>Reemplaza los contenidos de app.component.css con el siguiente código:</strong></p>
<pre><code class="lang-css"><span class="hljs-selector-class">.app-container</span> {
    <span class="hljs-attribute">display</span>: flex;
    <span class="hljs-attribute">flex-direction</span>: column;
    <span class="hljs-attribute">position</span>: absolute;
    <span class="hljs-attribute">top</span>: <span class="hljs-number">0</span>;
    <span class="hljs-attribute">bottom</span>: <span class="hljs-number">0</span>;
    <span class="hljs-attribute">left</span>: <span class="hljs-number">0</span>;
    <span class="hljs-attribute">right</span>: <span class="hljs-number">0</span>;
}

<span class="hljs-selector-class">.app-is-mobile</span> <span class="hljs-selector-class">.app-toolbar</span> {
    <span class="hljs-attribute">position</span>: fixed;
    <span class="hljs-attribute">z-index</span>: <span class="hljs-number">2</span>;
}

<span class="hljs-selector-tag">h1</span><span class="hljs-selector-class">.app-app-name</span> {
    <span class="hljs-attribute">margin-left</span>: <span class="hljs-number">8px</span>;
}

<span class="hljs-selector-class">.app-sidenav-container</span> {
    <span class="hljs-attribute">flex</span>: <span class="hljs-number">1</span>;
}

<span class="hljs-selector-class">.app-is-mobile</span> <span class="hljs-selector-class">.app-sidenav-container</span> {
    <span class="hljs-attribute">flex</span>: <span class="hljs-number">1</span> <span class="hljs-number">0</span> auto;
}
</code></pre>
<h2 id="heading-paso-5-ejecutar-nuestra-aplicacion"><strong>PASO 5: EJECUTAR NUESTRA APLICACIÓN</strong></h2>
<p>En la consola integrada de Visual Studio Code, ejecuta la aplicación.</p>
<pre><code class="lang-bash">ng serve --open
</code></pre>
<p>Listo. Tenemos nuestra primera aplicación con Angular 8 y Material UI.</p>
<p><img src="https://rckstr1.github.io/images/blog/AngularMaterial/06-ItWorks.png" alt /></p>
<h2 id="heading-conclusion"><strong>CONCLUSIÓN</strong></h2>
<p>En este post vimos los pasos necesarios para utilizar componentes de Material Design en nuestras aplicaciones con Angular.</p>
<p>Ahora estas listo para experimentar con Angular 8 y los componentes de Material UI.</p>
<p>El código fuente completo de la aplicación de ejemplo puedes encontrarlo en GitHub, en <a target="_blank" href="https://github.com/RCKSTR1/AngularMaterial">https://github.com/RCKSTR1/AngularMaterial</a> o si prefieres, puedes clonar el repositorio directo en <a target="_blank" href="https://github.com/RCKSTR1/AngularMaterial.git">https://github.com/RCKSTR1/AngularMaterial.git</a></p>
<p>Si tuviste algún problema o duda al seguir los pasos, o si tienes alguna pregunta acerca de este post, contáctame en Twitter, Facebook o LinkedIn.</p>
<p><strong>Es cuánto.</strong></p>
<h2 id="heading-fuentes"><strong>FUENTES</strong></h2>
<ul>
<li>Documentación de Angular Material. <a target="_blank" href="https://material.angular.io/guide/getting-started">https://material.angular.io/guide/getting-started</a></li>
</ul>
]]></content:encoded></item><item><title><![CDATA[¡Hola angular 8!]]></title><description><![CDATA[[Publicado el 30 de Mayo, 2023 en rckstr1.github.io]
Introducción
Angular es un framework javascript muy popular, usado para desarrollar aplicaciones web, de escritorio y móviles. El desarrollo de aplicaciones con angular, involucra html, css y types...]]></description><link>https://publicvoid.hashnode.dev/hola-angular-8</link><guid isPermaLink="true">https://publicvoid.hashnode.dev/hola-angular-8</guid><category><![CDATA[Angular]]></category><dc:creator><![CDATA[Adrian Gonzalez]]></dc:creator><pubDate>Sat, 01 Apr 2023 23:41:02 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1680388862657/096fa24a-df27-4cfc-a32c-faf7c36a0ec2.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><a target="_blank" href="https://rckstr1.github.io/2019/05/30/HolaAngular8.html">[Publicado el 30 de Mayo, 2023 en rckstr1.github.io]</a></p>
<h2 id="heading-introduccion">Introducción</h2>
<p>Angular es un framework javascript muy popular, usado para desarrollar aplicaciones web, de escritorio y móviles. El desarrollo de aplicaciones con angular, involucra html, css y typescript que posteriormente es compilado a javascript.</p>
<p>Usar angular proporciona ventajas como:</p>
<h3 id="heading-1-soporte-para-single-page-applications-spa">1. Soporte para single page applications (spa)</h3>
<p>Spas son un tipo de aplicación web que cargan una sola página html, esta página es actualizada dinámicamente de acuerdo a la interacción del usuario con la aplicación sin tener que recargar la página completa.</p>
<h3 id="heading-2-two-way-data-binding">2. Two-way data binding</h3>
<p>Esta característica nos permite actualizar datos de manera automática en dos vías. Es decir, si nuestra fuente de datos cambia, la interfaz actualiza los datos, y viceversa.</p>
<h3 id="heading-3-modularidad">3. Modularidad</h3>
<p>Por diseño, el código de nuestra aplicación está organizado en módulos. Un módulo está relacionado a grupos de componentes, directivas, pipes y servicios.</p>
<p>La modularidad también provee otros beneficios en angular, como la habilidad de cargar solamente los componentes que necesitamos, conocida como lazy-loading.</p>
<h3 id="heading-4-requiere-escribir-menos-codigo">4. Requiere escribir menos código</h3>
<p>A todos nos gusta escribir menos código, que al mismo tiempo sea más efectivo. Angular soporta la arquitectura mvc (model-view-controller). Adaptarnos a este diseño nos permite escribir menos código y hace más fácil implementar buenas prácticas.</p>
<h3 id="heading-5-interfaz-de-usuario-declarativa">5. Interfaz de usuario declarativa</h3>
<p>Nos permite definir la interfaz de usuario utilizando html de manera intuitiva y menos compleja que hacerlo con javascript. No tenemos que preocuparnos por el orden en que se cargan los componentes o el flujo del programa.</p>
<p>En los últimos días, se liberó la versión 8 de angular. En esta versión se mejoraron los tiempos de arranque de las aplicaciones y se incluyen nuevos api para interactuar con la cli.</p>
<h2 id="heading-prerrequisitos">Prerrequisitos</h2>
<p>Para sacar el mayor provecho de angular necesitas conocer un poco de:</p>
<ul>
<li><p>Html</p>
</li>
<li><p>Typescript</p>
</li>
<li><p>Css</p>
</li>
</ul>
<h2 id="heading-paso-1-obtener-las-herramientas">Paso 1: obtener las herramientas</h2>
<p>Antes que nada, debemos contar con algunas herramientas instaladas en nuestra computadora. Como yo ya tenía las herramientas instaladas, creé una máquina virtual con elementary os, una distribución de linux basada en debian.</p>
<h3 id="heading-nodejs">Node.js</h3>
<p>Angular, angular cli y las aplicaciones con angular dependen de librerías disponibles como paquetes de npm.</p>
<h4 id="heading-en-linux-debian">En linux (debian)</h4>
<p>Los siguientes comandos funcionan en distribuciones de linux basadas en debian. En la terminal del sistema, ejecuta las siguientes líneas:</p>
<pre><code class="lang-bash">sudo curl -sL https://deb.nodesource.com/setup_12.x | sudo bash -
sudo apt-get install -y nodejs
</code></pre>
<h4 id="heading-en-windows-o-macos"><strong>EN WINDOWS O MACOS</strong></h4>
<p><img src="https://rckstr1.github.io/images/blog/Angular8/01-NodeInstall.png" alt /></p>
<ol>
<li><p>Utilizando cualquier navegador, ve a <a target="_blank" href="http://www.nodejs.org">www.nodejs.org</a> y descarga la versión más reciente.</p>
</li>
<li><p>Ejecuta el archivo descargado e instala Node.js.</p>
</li>
<li><p>Antes de continuar al siguiente paso, comprobamos la instalación ejecutando la siguiente línea en la terminal:</p>
<pre><code class="lang-bash"> npm -v
</code></pre>
<h3 id="heading-angular-cli"><strong>ANGULAR CLI</strong></h3>
<p> <img src="https://rckstr1.github.io/images/blog/Angular8/02-AngularCLIInstall.png" alt /></p>
<p> La interfaz de línea de comandos o CLI, es una herramienta que usaremos para inicializar, desarrollar y mantener nuestras aplicaciones. Para instalar Angular CLI ejecuta la siguiente línea en la terminal (es posible que necesites permisos de root o administrador):</p>
<pre><code class="lang-bash"> npm install -g @angular/cli
</code></pre>
<h3 id="heading-visual-studio-code-o-cualquier-otro-editor-de-codigo"><strong>VISUAL STUDIO CODE (O CUALQUIER OTRO EDITOR DE CÓDIGO)</strong></h3>
<p> <img src="https://rckstr1.github.io/images/blog/Angular8/03-VSCodeDownload.png" alt /></p>
<p> Este paso es opcional. Puedes usar el editor de código que más te guste. Visual Studio Code es mi favorito por la cantidad de extensiones disponibles y la terminal integrada. Si prefieres no usar Visual Studio Code puedes omitir esta parte.</p>
<ol>
<li><p>Utilizando cualquier navegador, ve a <a target="_blank" href="http://code.visualstudio.com">code.visualstudio.com</a></p>
</li>
<li><p>Descarga el instalador</p>
<p> Las opciones de descarga varían dependiendo de tu Sistema operativo. Si estas usando Linux, tienes la opción de descargar un archive .deb o .rpm, como estoy usando Elementary OS, descargué el archivo .deb.</p>
</li>
<li><p>Instala la aplicación</p>
<p> En mi caso, ya tenía preinstalado “Eddy” como manejador de paquetes, puedes instalar “Eddy” o cualquier otro manejador de paquetes dependiendo de la distribución de Linux que estés utilizando.</p>
<p> Por otro lado, si estas en Windows o MacOS, no tienes de que preocuparte. Simplemente haz clic en el botón de descarga e instala Visual Studio Code como cualquier otra aplicación.</p>
</li>
</ol>
</li>
</ol>
<h4 id="heading-extensiones-recomendadas"><strong>EXTENSIONES RECOMENDADAS</strong></h4>
<p>Esta parte también es opcional. Aunque puedes optar por utilizar Visual Studio Code sin instalar extensiones, recomiendo usar estas extensiones porque agregan características al editor y nos puede hacer el trabajo más fácil a corto y mediano plazo.</p>
<p>En la ventana de Visual Studio Code, haz clic en el último botón de la barra de actividades en el lado izquierdo para abrir la vista de extensiones.</p>
<h5 id="heading-angular-language-service"><strong>ANGULAR LANGUAGE SERVICE</strong></h5>
<p><img src="https://rckstr1.github.io/images/blog/Angular8/04-AngularLanguageService.png" alt /></p>
<p>Esta extensión provee una mejor experiencia al trabajar con plantillas de Angular con características como listas de autocompletado, mensajes de diagnóstico AOT, opciones para ver la definición de variables u objetos.</p>
<ol>
<li><p>En el campo de búsqueda, escribe “Angular” (sin comillas).</p>
</li>
<li><p>En la lista de resultados, selecciona la extensión “Angular Language Service” y después haz clic en “Install”</p>
</li>
</ol>
<h5 id="heading-tslint"><strong>TSLINT</strong></h5>
<p><img src="https://rckstr1.github.io/images/blog/Angular8/05-TSLint.png" alt /></p>
<p>TSLint es una herramienta de análisis de código TypeScript que revisa legibilidad, facilidad de mantenimiento y errores de funcionalidad. Puede personalizarse con tus propias reglas, configuraciones y formateadores.</p>
<ol>
<li><p>En el campo de búsqueda, escribe “TSLint” (sin comillas).</p>
</li>
<li><p>En la lista de resultados, selecciona la extensión “TSLint” de Microsoft y después haz clic en “Install”.</p>
</li>
</ol>
<h5 id="heading-visual-studio-intellicode"><strong>VISUAL STUDIO INTELLICODE</strong></h5>
<p><img src="https://rckstr1.github.io/images/blog/Angular8/06-IntelliCode.png" alt /></p>
<p>Esta extensión provee características asistidas por inteligencia artificial para varios lenguajes de programación basadas en contexto y machine learning.</p>
<ol>
<li><p>En el campo de búsqueda, escribe “IntelliCode” (sin comillas).</p>
</li>
<li><p>En la lista de resultados, selecciona la extensión “Visual Studio IntelliCode” y después haz clic en “Install”.</p>
</li>
</ol>
<h4 id="heading-tipo-de-letra-fira-code-opcional"><strong>TIPO DE LETRA FIRA CODE (OPCIONAL)</strong></h4>
<p><img src="https://rckstr1.github.io/images/blog/Angular8/12-FiraCode.png" alt /></p>
<p>Fira Code es una extensión del tipo de letra Fira Mono, que contiene ligaduras para combinaciones multicaracter más comunes en programación. Esta característica ayuda a leer y entender código más rápidamente.</p>
<ol>
<li><p>Utilizando cualquier navegador, ve a <a target="_blank" href="http://github.com/tonsky/FiraCode">github.com/tonsky/FiraCode</a> y descarga los archivos del repositorio</p>
</li>
<li><p>Instala el tipo de letra en tu computadora. En mi caso, instalé los archivos OpenType.</p>
</li>
</ol>
<h5 id="heading-configurar-fira-code-en-visual-studio-code"><strong>CONFIGURAR FIRA CODE EN VISUAL STUDIO CODE</strong></h5>
<ol>
<li><p><img src="https://rckstr1.github.io/images/blog/Angular8/07-FiraCodeSettings.png" alt /></p>
</li>
<li><p>En la ventana de Visual Studio Code, presiona CTRL+, en Windows o Linux, o CMD+, en MacOS para abrir la pantalla de configuración.</p>
</li>
<li><p>Una vez en la pantalla de configuración, haz clic en “Text Editor” y después en la opción “Font”.</p>
</li>
<li><p>En el campo “Font Family” escribe “Fira Code” (sin comillas).</p>
</li>
<li><p>Activa la casilla “Font Ligatures”</p>
</li>
</ol>
<h2 id="heading-paso-2-crear-nuestra-primera-app-con-angular-8"><strong>PASO 2: CREAR NUESTRA PRIMERA APP CON ANGULAR 8</strong></h2>
<p><img src="https://rckstr1.github.io/images/blog/Angular8/08-CreateApp.png" alt /></p>
<ol>
<li><p>Desde la terminal, navega al folder en donde quieres crear tu aplicación. Yo decidí crear un folder nuevo para guardar mis apps.</p>
</li>
<li><p>Una vez dentro del folder donde vas a crear tu app, escribe el siguiente comando:</p>
<pre><code class="lang-bash"> ng new [nombre de tu app]
</code></pre>
<p> Angular CLI comenzará a crear tu aplicación y te presentará algunas opciones. Primero debes indicar si quieres agregar Angular Routing a tu app, por lo general vas a necesitarlo, selecciona la opción para agregarlo.</p>
</li>
<li><p>Después, debes especificar el formato de estilos que va a usar la aplicación, para este caso selecciona CSS.</p>
</li>
<li><p>Por último, indica si deseas compartir datos de uso con Google.</p>
<p> Ahora verifica que se creó un folder con el nombre de tu nueva aplicación.</p>
</li>
</ol>
<h3 id="heading-ejecuta-la-aplicacion"><strong>EJECUTA LA APLICACIÓN</strong></h3>
<p><img src="https://rckstr1.github.io/images/blog/Angular8/09-VSCodeOpenFolder.png" alt class="image--center mx-auto" /></p>
<p>A partir de este paso, comienza a utilizar la terminal integrada de Visual Studio Code, si prefieres otro editor de código, puedes seguir usando la terminal de tu sistema operativo para ejecutar comandos.</p>
<ol>
<li><p>Abre Visual Studio Code y haz clic en el primer icono de la barra de actividad para mostrar el explorador de archivos.</p>
</li>
<li><p>Haz clic en el botón “Open Folder” y selecciona el folder de tu nueva aplicación para que Visual Studio Code muestre los contenidos de tu aplicación en el explorador de archivos.</p>
</li>
<li><p>En la barra de menú, has clic en “View” y después en la opción “Terminal” para abrir la terminal integrada.</p>
</li>
<li><p>Desde esta terminal puedes ejecutar tu aplicación escribiendo:</p>
<pre><code class="lang-bash"> ng serve --open
</code></pre>
<p> <img src="https://rckstr1.github.io/images/blog/Angular8/10-VSCodeConsole.png" alt /></p>
<p> El modificador "--open" es opcional. La diferencia es que si usas “-- open” la aplicación se abre automáticamente en tu navegador predeterminado, de otra manera, tendrías que ejecutar cualquier navegador y abrir <a target="_blank" href="http://localhost:4200">http://localhost:4200</a>.</p>
<p> Mientras la aplicación se está ejecutando, la ventana del navegador se actualiza automáticamente después de guardar cualquier cambio en tu código.</p>
<p> Para dejar de ejecutar tu aplicación, presiona CTRL+C en la terminal.</p>
</li>
</ol>
<h2 id="heading-conclusion"><strong>CONCLUSIÓN</strong></h2>
<p><img src="https://rckstr1.github.io/images/blog/Angular8/11-AppRuns.png" alt /></p>
<p>Ahora ya tienes lo necesario para comenzar a escribir aplicaciones web, móviles o de escritorio con Angular 8.</p>
<p>El código fuente completo de la aplicación de ejemplo puedes encontrarlo en GitHub, en <a target="_blank" href="https://github.com/RCKSTR1/Angular8RCSTR-APP">https://github.com/RCKSTR1/Angular8RCSTR-APP</a> o si prefieres, puedes clonar el repositorio directo en <a target="_blank" href="https://github.com/RCKSTR1/Angular8RCSTR-APP.git">https://github.com/RCKSTR1/Angular8RCSTR-APP.git</a></p>
<p>Si tuviste algún problema o duda al seguir los pasos, o si tienes alguna pregunta acerca de este post, contáctame en Twitter, Facebook o LinkedIn.</p>
<p><strong>Es cuánto.</strong></p>
<h2 id="heading-fuentes"><strong>FUENTES</strong></h2>
<ul>
<li><p>Documentación de Angular. <a target="_blank" href="https://angular.io/docs">https://angular.io/docs</a></p>
</li>
<li><p>Guía de setup de Angular. <a target="_blank" href="https://angular.io/guide/setup-local">https://angular.io/guide/setup-local</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Hello World]]></title><description><![CDATA[[Publicado el 27 de Mayo, 2019. En rckstr1.github.io]
Mi nombre es Adrian, soy de Tijuana, Baja California, “la ciudad mas peligrosa del mundo” dicen algunos. Pero a mi no me ha traído mas que cosas buenas. Aquí nací y crecí. Es una ciudad llena de o...]]></description><link>https://publicvoid.hashnode.dev/hello-world</link><guid isPermaLink="true">https://publicvoid.hashnode.dev/hello-world</guid><dc:creator><![CDATA[Adrian Gonzalez]]></dc:creator><pubDate>Sat, 01 Apr 2023 22:38:09 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1680388553829/df428369-58e7-47d5-addc-20ecfc2601b8.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><a target="_blank" href="https://rckstr1.github.io/2019/05/27/HelloWorld.html">[Publicado el 27 de Mayo, 2019. En rckstr1.github.io]</a></p>
<p>Mi nombre es Adrian, soy de Tijuana, Baja California, “la ciudad mas peligrosa del mundo” dicen algunos. Pero a mi no me ha traído mas que cosas buenas. Aquí nací y crecí. Es una ciudad llena de oportunidades, que tiene oídos para las buenas ideas, sin importar de donde vengan.</p>
<p>Soy de los afortunados que tuvieron la oportunidad de convertirse en lo que querían ser desde niños. Yo no quería ser ni bombero ni astronauta, sino que esperaba los días de escuela en que nos llevaban al laboratorio de computación, a dibujar en Paint con Windows 95, o jugar algún juego en la computadora.</p>
<p>Un día, cuando tenía 8 años, en lugar de abrir Word, o Paint, llegamos al laboratorio y en las pantallas había una ventana desconocida, era el IDE de LOGO. La profesora Vicky nos contó una historia acerca de una tortuga, y escribió en el pizarrón 4 “palabras mágicas” necesarias para mover a la tortuga. Ese fue el día que escribí mi primera línea de código, Ahora podía hacer dibujos escribiendo líneas de código y ver como se iban dibujando en la pantalla. Y ya. Desde entonces lo que yo quería hacer era tener una computadora y escribir código para hacer dibujos y regalárselos a todo el mundo.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1680388337350/7a3b104e-4c63-475d-9ae7-50531aace15f.png" alt="LOGO. Existe una version moderna del ide online: https://turtleacademy.com/" class="image--center mx-auto" /></p>
<p>Pasaron algunos años, y ahora estaba en la universidad. Con las mismas ganas de escribir código en una computadora, pero ahora acompañado de personas que igual que yo, habían decidido en algún punto de sus vidas, escribir código, o hacer redes, o diseñar microprocesadores.</p>
<p>Fast forward al 2019, tengo 31 años, soy desarrollador de software, desde 2007 especializado en tecnologías de Microsoft, aunque últimamente incursionando en la realidad aumentada. Hace un año, recibí la invitación de LinkedIn para el programa de Career Advisors, me pareció una manera interesante de contribuir a otros con mi grano de arena. Sin embargo, hace tiempo que me vengo dando cuenta de los efectos que la barrera del lenguaje tiene en el desarrollo de software, de la desventaja que puede representar para las personas que no pueden adquirir conocimiento porque no han tenido el tiempo o la oportunidad de aprender inglés.</p>
<p>Este blog es mi manera de decir gracias a todos de los que he aprendido algo y que de alguna manera me ayudaron a convertirme en lo que siempre quise desde que era un niño.</p>
<p>Sinceramente, espero alguno de estos días poder escribir algo que le ayude a alguien a escribir su primera línea de código.</p>
<p><strong>Es cuánto.</strong></p>
]]></content:encoded></item></channel></rss>