{"id":22115923,"url":"https://github.com/uspiri/angular-guideline","last_synced_at":"2025-03-24T05:29:58.189Z","repository":{"id":110730938,"uuid":"569589827","full_name":"USpiri/angular-guideline","owner":"USpiri","description":"Serie de lineamientos para la estructura, organización y buenas prácticas de proyectos en Angular","archived":false,"fork":false,"pushed_at":"2022-11-24T20:30:07.000Z","size":31,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-01-29T11:21:30.245Z","etag":null,"topics":["angular","angular-architecture","best-practices","guidelines","project-management","recomendations"],"latest_commit_sha":null,"homepage":"https://github.com/USpiri/angular-guideline/","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/USpiri.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2022-11-23T07:07:09.000Z","updated_at":"2024-10-18T02:12:27.000Z","dependencies_parsed_at":"2023-03-22T13:47:00.700Z","dependency_job_id":null,"html_url":"https://github.com/USpiri/angular-guideline","commit_stats":{"total_commits":5,"total_committers":2,"mean_commits":2.5,"dds":"0.19999999999999996","last_synced_commit":"fc6c48da6ede7959982ee8c799c18fb2ffef7e07"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/USpiri%2Fangular-guideline","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/USpiri%2Fangular-guideline/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/USpiri%2Fangular-guideline/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/USpiri%2Fangular-guideline/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/USpiri","download_url":"https://codeload.github.com/USpiri/angular-guideline/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245215972,"owners_count":20579083,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["angular","angular-architecture","best-practices","guidelines","project-management","recomendations"],"created_at":"2024-12-01T12:18:18.878Z","updated_at":"2025-03-24T05:29:58.164Z","avatar_url":"https://github.com/USpiri.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"\n# **Angular architecture, recommendations and good practices**\n\nSerie de lineamientos para la estructura, organización y buenas prácticas de proyectos en Angular, ayudando a escribir código limpio y mantener un standar de código y performance.  \nEste artículo no pretende ser una guía explicando cada concepto de Angular, tampoco ser reglas estrictas, como indica el título son recomendaciones.\n\n## Indice:\n\n- [Angular](#angular)\n- [Versión de Angular](#version-de-angular)\n- [Angular CLI](#usar-angular-cli)\n- [Comandos utiles](#comandos-utiles)\n- [Angular Coding Style](#angular-coding-style)\n- [Angular Configuration](#angular-configuration)\n- [Angular Modules](#angular-modules)\n- [Angular Components](#angular-components)\n- [Angular Standalone Components](#angular-standalone-components)\n- [File naming](#file-naming)\n- [Folder Structure](#folder-structure)\n- [Barrels](#barrels)\n- [Lazy Loading](#lazy-loading)\n- [Data Infrastructure](#data-infrastructure)\n- [Spinner](#spinner)\n- [Pipes](#pipes)\n- [Observables](#observables)\n- [Angular Material](#angular-material)\n\n\n## **Angular**  \n\nAngular es un Framework de JavaScript de código abierto escrito en **TypeScript**. Su objetivo principal es desarrollar aplicaciones de una sola página. Google se encarga del mantenimiento y constantes actualizaciones de mejoras para este framework.  \n\n#### Version de Angular\n\nEsta guideline fue creada pensando en la versión de **Angular 14**\n\n## **Usar Angular CLI**\n\n[Angular CLI](https://cli.angular.io/) es la herramienta por defecto a la hora de desarrollar una app en Angular. Este CLI facilita la creación de la aplicación siguiendo con buenas prácticas por lo que un buen consejo es **Usar Angular CLI** para generar los nuevos componentes, directivas, módulos, servicios y pipes.\n\n#### Comandos utiles\n\n```c\n// Instalar Angular CLI\nnpm install -g @angular/cli\n\n// Verificar la versión instalada\nng version\n\n// Iniciar un nuevo proyecto Angular\nng new \u003capp-name\u003e\n\n// Generar un nuevo componente\nng generate component|directive|module|service|pipe \u003ccomponent-name\u003e\n\n// Ejecutar la aplicación localmente\nng serve\n\n// Instalar dependencia\nnpm install @\u003cdependency-name\u003e\n\n// Agregar dependencia\nng add @\u003cdependency-name\u003e\n```\n\n## **Angular Coding Style**\n\nSerie de lineamientos descriptos en [Angular Coding Style](https://angular.io/guide/styleguide) que se repetirán a lo largo del documento. Estas son algunas de las reglas que se necesitan seguir para que un proyecto cumpla con el standard de Angular style guide:\n\n1. Limitar **archivos a 400 líneas de código**, considerar atomizar.\n2. Definir **funciones pequeñas** y específicas, limitándolas a **75 líneas**.\n3. Mantener la **consistencia en la nomenclatura**.\n4. Si existen **variables que deben permanecer intactas**, declararlas como **\"const\"**.\n5. El nombre de las **propiedades y los métodos** deben **SIEMPRE** el minúsculas y **camelCase**\n6. **Siempre dejar un salto de línea entre los imports** y los módulos como así también entre las importaciones de terceros y de los módulos personalizados.\n7. **Utilizar prefijos personalizados** para prevenir que los nombres de los elementos entren en conflicto con otros componentes o incluso con componentes nativos de HTML.\n8. **Nunca** se deberá **nombrar a una interface con la primer letra mayúscula \"I\"** como se suele hacer en otros lenguajes de programación,\n9. Seguir en mayor medida el **principio de Single Responsibility**.\n10. Es importante **no crear más de un componente|servicio|directiva dentro de una misma carpeta**, esto viola el principio de Single Responsibility.\n\n## **Angular Configuration**\n\nAlgunas modificaciones a los archivos de configuración creados por defecto que nos facilitarán el acceso o la legibilidad del código.\n\n### **Path alias (tsconfig.json)**\n\nRepresentan atajos para acceder a nuestros archivos permitiéndonos implementar imports más cortos que faciliten la comprensión.\n\n```json\n\"paths\":{\n   \"@src/*\":[\n      \"src/*\"\n   ],\n   \"@assets/*\":[\n      \"src/assets/*\"\n   ],\n   \"@shared/*\":[\n      \"src/app/shared/*\"\n   ]\n}\n```\n\n### **Angular Configuration (angular.json)**\n\nEs solo una recomendación disponible para usar a la hora de compilar nuestra aplicación.   \nReemplaza el archivos de environments por environments.local en caso de que se trabaje en desarrollo y environments.prod para producción.\n\n```json\n\"configurations\": {\n    \"development\": {\n        \"budgets\": [\n            {\n                \"type\": \"initial\",\n                \"maximumWarning\": \"2mb\",\n                \"maximumError\": \"5mb\"\n            }\n        ],\n        \"fileReplacements\": [\n            {\n                \"replace\": \"src/environments/environment.ts\",\n                \"with\": \"src/environments/environment.local.ts\"\n            }\n        ],\n        \"optimization\": false,\n        \"buildOptimizer\": false,\n        \"vendorChunk\": true,\n        \"extractLicenses\": false,\n        \"sourceMap\": true,\n        \"namedChunks\": true\n    },\n    \"production\": {\n        \"budgets\": [\n            {\n                \"type\": \"initial\",\n                \"maximumWarning\": \"2mb\",\n                \"maximumError\": \"5mb\"\n            }\n        ],\n        \"fileReplacements\": [\n            {\n                \"replace\": \"src/environments/environment.ts\",\n                \"with\": \"src/environments/environment.prod.ts\"\n            }\n        ],\n        \"optimization\": true,\n        \"buildOptimizer\": true,\n        \"vendorChunk\": false,\n        \"outputHashing\": \"all\",\n        \"extractLicenses\": true,\n        \"sourceMap\": false,\n        \"namedChunks\": false\n    }\n}\n```\n\n## **Angular Modules**\n\nAntes de introducir la estructura de carpetas (Folder structure) vamos a definir el concepto y uso de módulos. Angular se basa en el principio de *Separar responsabilidades*, la esencia de este principio es que el código debe desarrollarse y agruparse de tal forma que cada una tenga una\"***Responsabilidad única***\". Los módulos son un grupo de componentes, servicios y pipes que trabajan en conjunto para proporcionar un \"*Conjunto de características/funciones específicas*\".  \nEsta práctica hace posible la implementación del Lazy Loading junto con la carga de Children Components, tema que se abordará más adelante.\n\n## **Angular Components**  \n\n### **Atomizar componentes**\n\nEste punto debería considerarse como extensión del principio de single responsibility aplicado no solo a las carpetas y al código, sino que a los componentes también. En donde se crea cada componente con el fin de ejecutar una función específica. Mientras más largo se vuelva un componente, más difícil será mantenerlo e iterar sobre él.   \nSi un componente se comienza a tornar demasiado grande, lo ideal es descomponerlo en componentes más pequeños, más manejables y dedicados a funciones muy específicas.  \nRecordar que una buena práctica es **limitar los componentes a 400 líneas de código**.\n\n### **Reutilizar componentes**\n\nSi exite alguna parte de la interfaz de usuario (UI) que se necesite usar en muchos sitios de nuestra aplicación, crearemos un componente externo que luego haremos uso del mismo donde se necesite. Esta acción, a la larga, terminará ahorrando tiempo cuando por ejemplo se requiera hacer un cambio a la IU. Para este caso no tendremos que buscar en todos los archivos el la parte de la UI que queramos modificar, solo tendremos que modificar el componente.\n\n### **Component selectors**\n\nPara los selectores de componente, en caso de que decidamos cambiar el que se crea por defecto con el CLI, debe usarse dashed-case o kebab-case.  \n**Utilizar prefijos personalizados** para prevenir que los nombres de los elementos entren en conflicto con otros componentes o incluso con componentes nativos de HTML e  identificar a la \"característica/funcionalidad\" a la que pertenece el componente.  \n\n```c\n// Usar\n    \u003cprefix\u003e-custom-button\n\n// Evitar\n    prefixCustomButton\n```\n\n## **Angular Standalone Components**\n\nEl término \"standalone\" se refiere a componentes, directivas o pipes que pueden ser usadas independientemente de un NgModule. En esta página se encuentra el funcionamiento y creación de ellos. [Angular Standalone Components](https://www.telerik.com/blogs/angular-14-introducing-standalone-components)\n\n## **File naming**\n\nMantener la **consistencia en la nomenclatura** se vuelve muy importante para la mantención y legibilidad de código, también ayuda a encontrar más rápido el contenido deseado.\n\n### **Separar el nombre de los archivos con puntos y guiones**\n\nUsaremos los guiones (\"**-**\") para separar palabras dentro del *nombre descriptivo* para el archivo y puntos (\"**.**\") para separar el anterior del tipo de archivo. El patrón recomendado es:  \n\n```c\n\u003cdescriptive-name\u003e.\u003ctype\u003e.ts|.css|.html\n\n// Ejemplo\nfeature-name.component.ts\n\n// Evitar\nfeatureName.compnt.ts\n```\n\nLos tipos de archivos convencionales dentro de Angular son `.service`, `.component`, `.pipe`, `.module`, `.directive`. Adicionalmente se pueden crear \"tipos\" propios pero *no se recomienda crear demasiados*. Estos **no deben ser nombres abreviados** (Como `.srvc`) para evitar confusiones y **deben ser descriptivos e inequívocos**.  \n\n## **Folder Structure**\n\nDefinir la folder structure es un factor importante a considerar a la hora de crear nuestro proyecto. Nuestra estructura deberá adaptarse fácilmente a los nuevos cambios que surjan durante el desarrollo.  \nLa siguiente estructura fue creada con un módulo \"home\" de ejemplo, junto con algunos componentes y determinadas carpetas bajo el supuesto de que se utiliza [Angular Material](https://material.angular.io/). Debajo se explicará cada carpeta y archivo graficado.\n\n```\n.\n├── app/\n│   ├── components/\n│   │   ├── shared-component/\n│   │   │   └── shared-component.component.css|.html|.spec.ts|.ts\n│   │   └── ...\n│   ├── models/\n│   │   └── home.interface.ts\n│   ├── modules/\n│   │   ├── home/\n│   │   │   ├── components/\n│   │   │   │   ├── home-button/\n│   │   │   │   │   └── home-button.component.css|.html|.spec.ts|.ts\n│   │   │   │   ├── dialogs/\n│   │   │   │   │   ├── home-dialog/...\n│   │   │   │   │   └── home-table-dialog/...\n│   │   │   │   └── ...\n│   │   │   ├── services/\n│   │   │   │   ├── home.service.ts\n│   │   │   │   ├── home.service.spec.ts\n│   │   │   │   └── ...\n│   │   │   ├── shared/\n│   │   │   │   ├── materials/\n│   │   │   │   │   └── materials.module.ts\n│   │   │   │   ├── pipes/\n│   │   │   │   │   ├── home.pipe.ts\n│   │   │   │   │   └── ...\n│   │   │   │   └── directives/...\n│   │   │   ├── home-routing.module.ts\n│   │   │   ├── home.component.css|.html|.spec.ts|.ts\n│   │   │   └── home.module.ts\n│   │   └── another-module/...\n│   ├── services/...\n│   ├── shared/\n│   │   ├── animations/\n│   │   │   ├── animations.module.ts\n│   │   │   └── ...\n│   │   ├── directives/\n│   │   │   └── ...\n│   │   └── pipes/\n│   │       └── ...\n│   ├── app-routing.module.ts\n│   ├── app.component.css|.html|.spec.ts|.ts\n│   └── app.module.ts\n├── assets/\n│   ├── data/...\n│   ├── fonts/...\n│   └── images/...\n├── environments/\n│   ├── environment.local.ts\n│   └── environment.prod.ts\n├── styles/\n│   ├── custom-theme.scss\n│   ├── component-theme.scss\n│   └── ...\n├── index.html\n├── styles.css\n├── main.ts\n└── polyfills.ts\n  \n```\n\n### **Descripción**\n\nLa idea principal es separar las funciones/lógica de manera organizada y por categorías. Cada módulo (De `./app/modules`) deberá contenerse a sí mismo y no depender de otros (Independencia) para reforzar el concepto de Lazy Loading donde cada uno cargará *SOLO* si es necesario.  \nPara aquellos componentes, servicios, etc. que sean necesarios en más de un módulo (Ejemplo: módulos de Angular Material) se creará un shared.module (En `./app/shared`) para importarlos y que desde aquí sean exportados a toda la app.  \nPara los servicios compartidos es recomendable implementarlos directamente en `./app/app.module`. Ya que hacerlo en un shared.module podría implicar la creación de diferentes instancias del servicio imposibilitando la comunicación a lo largo de la aplicación.  \n\n- `./app/component`: Carpeta para componentes compartidos por varios módulos o componentes standalone.\n- `./app/models`: Carpeta de interfaces y clases. Archivos que podrán llamarse con el tipo \".interface\".\n- `./app/modules`: Carpeta principal de la app, aquí se encontrará cada módulo como se han definido previamente y conformarán un path distinto para nuestra app. Estos deben ser independientes el uno del otro.\n- `./app/services`: Carpeta para los servicios compartidos por varios módulos.\n- `./app/shared`: Carpeta para los recursos compartidos por varios módulos, como pipes, directives y animations.  \n- `./styles`: Carpeta para almacenar el theme de Angular Material junto con customizaciones de clases para el mismo.\n- `./environments/environment.local.ts`: Reemplazo de environment.ts por environment.local.ts (Explicado más adelante)\n\n### **Module sub-structure**\n\nCada módulo en `./app/modules` contendrá una sub-estructura similar a la que contiene el módulo principal (`./app`)  \n\n- `./app/modules/home/component`: Carpeta para componentes pertenecientes al módulo home.\n- `./app/modules/home/services`: Carpeta para los servicios utilizados por el módulo home.\n- `./app/modules/home/shared`: Carpeta para los recursos compartidos por los diferentes componentes del módulo home, como pipes, directives, animations y material modules.  \n- `./app/modules/home/home.module.ts`: Módulo home.\n- `./app/modules/home/home-routing.module.ts`: Módulo routing de home. Importante para la implementación de Lazy Loading\n- `./app/modules/home/home.component.css|.html|.spec.ts|.ts`: Componente principal home.  \n\n## **Barrels**\n\nPara ayudar a la organización del proyecto podemos utilizar conceptos como *\"Barrels\"*. La principal idea es agregar un archivo llamado \"index.ts\" para cada una de las carpetas que contengan un archivo .ts. Dentro de este se exportará cada una de las variables exportables de los .ts permitiendo crear una especie de jerarquía que nos va a ayudar a acortar largas cadenas de imports.  \nSon solo una recomendación ya que ellos no aparecen en la Angular Style Guide.\n\n#### **Ejemplo:**  \n\nSupongamos 3 componentes diferentes dentro de `./app/modules/home/component`:  \n\n```ts\nexport class SomeComponent {} \nexport class SomeClass {} \nexport class SomeService {} \n```\n\nSin Barrels necesitaríamos 3 imports diferentes para cada uno de estos componentes:\n\n```ts\nimport { SomeComponent } from '../component/some.component.ts';\nimport { SomeClass }     from '../component/some.model.ts'; \nimport { SomeService }   from '../component/some.service.ts'; \n```\n\nAgregando este barrel dentro de `./app/modules/home/component`  \n\n```ts\nexport * from './some.model.ts';   // re-export all of its exports \nexport * from './some.service.ts'; // re-export all of its exports \nexport { SomeComponent } from './some.component.ts'; // re-export the named thing \n```\n\nAhora solo tendríamos que importar lo que necesitemos de este barrel  \n\n```ts\nimport { SomeComponent, SomeService, SomeClass } from '../some'; // el archivo index está implicito\n```\n\n**Nota:** Esta [extensión](https://marketplace.visualstudio.com/items?itemName=mikehanson.auto-barrel) resulta muy útil para la implementacion de Barrels\n\n## **Lazy Loading**\n\nUna buena práctica es cargar de forma perezosa (lazy load) los módulos de nuestra aplicación siempre que sea posible. Obligando a que *SOLO* cargue lo necesario cuando sea necesario permitiendo que el tiempo de arranque de nuestra app disminuya considerablemente y nos brinde mayor seguridad al proyecto.  \n\n#### **Sin Lazy Loading**\n\n```ts\nimport ...;\n\nconst routes: Routes = [\n  { path: '', redirectTo: 'home', pathMatch: 'full' },\n  { path: 'home', component: HomeModule },\n  { path: '**', redirectTo: 'home' }\n];\n\n@NgModule({...})\nexport class AppRoutingModule { }\n```\n\n#### **Con Lazy Loading**\n\n```ts\nimport ...;\n\nconst routes: Routes = [\n  { path: '', redirectTo: 'home', pathMatch: 'full' },\n  { path: 'home', loadChildren: () =\u003e import('./modules').then( m =\u003e m.HomeModule ) },\n  { path: '**', redirectTo: 'home' }\n];\n\n@NgModule({...})\nexport class AppRoutingModule { }\n```\n\n## **Data Infrastructure**\n\n### **Variables intactas**\n\n**Las variables intactas (Que no van a ser modificadas) deben declarada como \"const\"** tal y como se indica en la guía de Angular.\n\n### **Evitar usar el tipo \"any\"**\n\nDeclarar variables o constantes con sus respectivos tipos evitará cometer errores involuntarios. Por lo que una buena práctica será intentar **siempre declarar el tipo de dato** en la medida que sea posible.\n\n```ts\n// Evitar errores de este tipo\n\nconst a = 1;\nconst b = 'dos';\nconst c = a + b;\n\nconsole.log('Valor de Z: ' + x); //Resultado no deseado = Valor de Z: 1dos\n\n// Aplicar el uso de tipos estrictos nos ayudará a prever\n\nconst a:number = 1;\nconst b:number = 'dos';\nconst c:number = a + b;\n\nconsole.log('Valor de Z: ' + x); \n\n// Esto nos devolverá un error de compilación avisando que 'dos' no es asignable a una variable de tipo number\n\n```\n\n### **Utilizar Interfaces**\n\nMediante el uso de interfaces podemos forzar que las clases implementen las funciones y propiedades que se extienden de la interface. Typescript no mostrará un error si un objeto no contiene todas las clases de nuestra interface.\n\n```ts\nexport interface SomeInterface {\n  text: string;\n  duration?: number;\n  color?: string;\n}\n```\n\nTambién es posible la utilización de `namespaces` para evitar confundir nuestra interface con otras clases distribuidas dentro de la aplicación  \n\n```ts\nexport namespace SomeNamespace {\n\n  interface LogOptions {\n    verbose?: boolean;\n  }\n\n  interface SomeInterface {\n    text: string;\n    duration?: number;\n    color?: string;\n  }\n\n}\n```\n\n### **Safe strings**\n\nLa declaración de \"Safe string\" puede ser muy beneficiosa en determinados casos. Estas variables (de tipo string) tienen la particularidad que siempre tienen solo un conjunto de valores posibles y nosotros podemos declarar una lista de ellos. Entonces la variable solo aceptará estos posibles valores y de esta forma evitar bugs inesperados mientras escribimos el código.\n\n```ts\n// Declaración normal de un string en donde podemos asignarle cualquier valor a un string\n\nprivate vehicleType: string;\nthis.vehicleType = 'four wheeler';\nthis.vehicleType = 'two wheeler';\nthis.vehicleType = 'car';\n\n// Declaración con Safe String\n\nprivate vehicleType: 'four wheeler' | 'two wheeler';\nthis.vehicleType = 'four wheeler';\nthis.vehicleType = 'two wheeler';\n\nthis.vehicleType = 'car'; // Esta linea nos va a retornar el siguiente error\n\nType '\"car\"' is not assignable to type '\"four wheeler\" | \"two wheeler\"'\n\n```\n\n### **Safe navigation operator (?)**\n\nA la hora de mostrar datos dentro de un template, si el objeto fuese null e intentamos acceder a alguna de sus propiedades, lo que obtendremos es una excepción, un error. Pero si utilizamos el Safe navigation operator (?) El template va a ignorar la variable nula y procederá a acceder a ella una vez deje de ser nula.\n\n```html\n\u003cspan\u003e{{ text?.value }}\u003c/span\u003e\n```\n\n## **Spinner**\n\nEl uso del spinner radica en informar al usuario que la carga de los datos (lo que utilizamos en el proyecto) están en proceso. Básicamente es un componente que muestra el estado de carga dentro de la aplicación. Este puede recibir un boolean para mostrarse u ocultarse.\n\n**load.service.ts**\n```tsx\nimport { Injectable } from '@angular/core';\nimport { AbstractControl } from '@angular/forms';\nimport { MatAutocomplete, MatAutocompleteSelectedEvent, MatChipInputEvent } from '@angular/material';\nimport { Subject } from 'rxjs';\n\nexport interface LoaderState {\n  show: boolean;\n}\n\n@Injectable({\n  providedIn: 'root'\n})\nexport class LoadService {\n\n  spinnerStatusState = new Subject\u003cany\u003e();\n  \n  constructor() {}\n  \n  displaySpinner(value: boolean) {\n    this.spinnerStatusState.next(\u003cLoaderState\u003e{ show: value });\n  }\n\n}\n```\n\n**app.component.ts**\n```tsx\nimport { Component, ChangeDetectionStrategy, OnInit } from '@angular/core';\nimport { LoadService } from './services/load.service';\n\n@Component({\n  selector: 'app-root',\n  templateUrl: './app.component.html',\n  styleUrls: ['./app.component.scss']\n})\nexport class AppComponent implements OnInit {\n\n  show = false;\n\n  constructor(private loadService: LoadService) {}\n\n  ngOnInit() {\n    this.loadService.spinnerStatusState.subscribe(state =\u003e {\n      setTimeout(() =\u003e {\n        this.show = state.show;\n      }, 0);\n    });\n  }\n\n}\n```\n\n**app.component.html**\n```html\n\u003cng-container\u003e\n  \u003cspan *ngIf=\"show\"\u003e\u003capp-spinner\u003e\u003c/app-spinner\u003e\u003c/span\u003e\n  \u003capp-navbar\u003e \u003crouter-outlet\u003e\u003c/router-outlet\u003e \u003c/app-navbar\u003e\n\u003c/ng-container\u003e\n```\n\n**spinner.component.ts**\n```tsx\nimport { Component, OnInit } from '@angular/core';\n\n@Component({\n  selector: 'app-spinner',\n  template: `\n    \u003cdiv class=\"loading\"\u003e\u003c/div\u003e\n  `,\n  styleUrls: ['./spinner.component.scss']\n})\nexport class SpinnerComponent implements OnInit {\n\n  constructor() {}\n\n  ngOnInit() {}\n  \n}\n```\n\n**Nota:** El estilo es a elección, incluso puede cambiarse por un gif o cualquier otra cosa que se quiera.\n\n**Cómo usarlo:**  \n\n Inyectar el servicio en el constructor del componente y después de llamar a un endpoint ejecutar: `this.loadService.displaySpinner(true);`\n\n## **Pipes**\n\nUna pipe es una herramienta que nos permite modificar o transformar la información presentada en pantalla. La data de la información no se modifica, sólo se transforma y se presenta de una determinada manera pero es sólo a efectos de presentación. Si bien su fin es solo estético, su implementación se basa en la reusabilidad y la simplificación de la arquitectura de un proyecto separando, posiblemente, procesos matemáticos o semánticos.\n\n```html\n\u003c!-- Esta pipe transforma el texto a uppercase --\u003e\n\u003cp\u003e{{ someString | uppercase }}\u003c/p\u003e\n```\n\n### Async Pipe\n\nLos observables pueden ser usados directamente en el template con las pipe async, cuando se destruye el componente que está usando el template el observable se desuscribe automáticamente.  \nSe vuelven útiles para mostrar en el componente los valores obtenidos y cancelar automáticamente la suscripción y así limitar las fugas de memoria innecesarias.\n\n**some.component.html**\n```html\n\u003cp\u003e{{ someString | async }}\u003c/p\u003e\n```\n\n**some.component.ts**\n```ts\nthis.text = observable.pipe(\n  map(value =\u003e value.item)\n);\n```\n\n## **Observables**\n\nSe pueden combinar los observables. Algunas veces nos encontraremos con que estamos llamando a más de un endpoint a la vez, entonces ¿Porqué no combinarlos?  \nEsto es posible gracias a `combineLatest` de rxjs. De esta forma, incluso si alguno de los valores no llega, podremos acceder al resultado (o error) de la suscripción.\n\n\n```tsx\nimport { combineLatest } from 'rxjs';\n\n...ngOnInit() {\n\n  combineLatest(\n    this.yourService.getObservable1(),\n    this.yourService.getObservable2()\n  ).subscribe(\n    ([result1, result2]) = {\n      ...\n    }\n  )\n\n}\n```\n\nDe esta forma resulta mucho más fácil desuscribirnos en el ngOnDestroy.  \n\n### **Unsuscribe**\n\nUna buena recomendación es que (Por más que Angular por defecto se desuscriba de las peticiones HTTP automáticamente), si se sabe que el observable va a traer información una única vez desde el back, usar `.pipe(first())` despues de suscribirnos al componente. De esta forma una vez obtenidos los datos el sistema se desuscribe solo.\n\nEn caso de necesitar una constante actualización de los datos utilizaremos el ngOnDestroy para desuscribirse del observable.\n\n```tsx\nprivate subs: Subscription | undefined;\n\nngOnDestroy(){\n  if (this.subs){\n    this.subs.unsuscribe():\n  }\n}\n\nprivate handleSubsOrder( orderId:string ){\n  this.subs = this.cartCheckoutFacade.startOrderFulfilmentPolling(irderId)\n}\n```\n\n## **Angular Material**\n\nhttps://kindly-windflower-254.notion.site/Angular-Material-as-a-base-for-reusable-components-6af5855328284905b4bd5a3a66354b91\n\nhttps://ngrx.io/guide/store\n\nhttps://materialtheme.arcsine.dev/\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fuspiri%2Fangular-guideline","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fuspiri%2Fangular-guideline","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fuspiri%2Fangular-guideline/lists"}