├── src ├── assets │ └── .gitkeep ├── app │ ├── app.component.scss │ ├── shared │ │ ├── footer │ │ │ ├── footer.component.scss │ │ │ ├── footer.component.html │ │ │ ├── footer.component.ts │ │ │ └── footer.component.spec.ts │ │ ├── navbar │ │ │ ├── navbar.component.scss │ │ │ ├── navbar.component.html │ │ │ ├── navbar.component.ts │ │ │ └── navbar.component.spec.ts │ │ ├── sidebar │ │ │ ├── sidebar.component.scss │ │ │ ├── sidebar.component.html │ │ │ ├── sidebar.component.ts │ │ │ └── sidebar.component.spec.ts │ │ ├── page-not-found │ │ │ ├── page-not-found.component.scss │ │ │ ├── page-not-found.component.html │ │ │ ├── page-not-found.component.ts │ │ │ └── page-not-found.component.spec.ts │ │ └── shared.module.ts │ ├── app.component.html │ ├── views │ │ ├── views.module.ts │ │ └── vista-de-prueba │ │ │ ├── vista-de-prueba.component.ts │ │ │ ├── vista-de-prueba.module.ts │ │ │ ├── vista-de-prueba-routing.module.ts │ │ │ ├── vista-de-prueba.component.spec.ts │ │ │ ├── vista-de-prueba.component.html │ │ │ └── vista-de-prueba.component.scss │ ├── app.component.ts │ ├── app.module.ts │ ├── app-routing.module.ts │ └── app.component.spec.ts ├── environments │ ├── environment.prod.ts │ └── environment.ts ├── favicon.ico ├── styles.scss ├── index.html ├── main.ts ├── test.ts └── polyfills.ts ├── e2e ├── features │ └── home.feature ├── plugins │ ├── index.js │ └── webpack.config.js ├── support │ ├── index.ts │ └── commands.ts ├── step_definitions │ └── home_steps.ts └── tsconfig.json ├── .editorconfig ├── tsconfig.app.json ├── tsconfig.spec.json ├── cypress.json ├── browserslist ├── tsconfig.json ├── .gitignore ├── karma.conf.js ├── package.json ├── tslint.json ├── angular.json └── README.md /src/assets/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/app.component.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/shared/footer/footer.component.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/shared/navbar/navbar.component.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/shared/sidebar/sidebar.component.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/app.component.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/app/shared/page-not-found/page-not-found.component.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/shared/footer/footer.component.html: -------------------------------------------------------------------------------- 1 |

footer works!

2 | -------------------------------------------------------------------------------- /src/app/shared/navbar/navbar.component.html: -------------------------------------------------------------------------------- 1 |

navbar works!

2 | -------------------------------------------------------------------------------- /src/app/shared/sidebar/sidebar.component.html: -------------------------------------------------------------------------------- 1 |

sidebar works!

2 | -------------------------------------------------------------------------------- /src/app/shared/page-not-found/page-not-found.component.html: -------------------------------------------------------------------------------- 1 |

page-not-found works!

2 | -------------------------------------------------------------------------------- /src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true 3 | }; 4 | -------------------------------------------------------------------------------- /src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbellod1986/boilerplate-angular-base/HEAD/src/favicon.ico -------------------------------------------------------------------------------- /src/styles.scss: -------------------------------------------------------------------------------- 1 | /* You can add global styles to this file, and also import other style files */ 2 | -------------------------------------------------------------------------------- /e2e/features/home.feature: -------------------------------------------------------------------------------- 1 | Feature: Home 2 | Home Description 3 | 4 | Scenario: Open page 5 | Given the user visit the main page 6 | Then page should have the right title 7 | 8 | -------------------------------------------------------------------------------- /src/app/views/views.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { CommonModule } from '@angular/common'; 3 | 4 | 5 | 6 | @NgModule({ 7 | declarations: [], 8 | imports: [ 9 | CommonModule 10 | ] 11 | }) 12 | export class ViewsModule { } 13 | -------------------------------------------------------------------------------- /src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-root', 5 | templateUrl: './app.component.html', 6 | styleUrls: ['./app.component.scss'] 7 | }) 8 | export class AppComponent { 9 | title = 'proyecto-base-angular'; 10 | } 11 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see https://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | max_line_length = off 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /e2e/plugins/index.js: -------------------------------------------------------------------------------- 1 | // const { addMatchImageSnapshotPlugin } = require('cypress-image-snapshot/plugin'); 2 | const webpack = require('@cypress/webpack-preprocessor'); 3 | 4 | module.exports = on => { 5 | const options = { 6 | webpackOptions: require('./webpack.config.js') 7 | }; 8 | on('file:preprocessor', webpack(options)); 9 | }; 10 | -------------------------------------------------------------------------------- /tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "./out-tsc/app", 5 | "types": [] 6 | }, 7 | "files": [ 8 | "src/main.ts", 9 | "src/polyfills.ts" 10 | ], 11 | "include": [ 12 | "src/**/*.d.ts" 13 | ], 14 | "exclude": [ 15 | "src/test.ts", 16 | "src/**/*.spec.ts" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "./out-tsc/spec", 5 | "types": [ 6 | "jasmine", 7 | "node" 8 | ] 9 | }, 10 | "files": [ 11 | "src/test.ts", 12 | "src/polyfills.ts" 13 | ], 14 | "include": [ 15 | "src/**/*.spec.ts", 16 | "src/**/*.d.ts" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /src/app/shared/footer/footer.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-footer', 5 | templateUrl: './footer.component.html', 6 | styleUrls: ['./footer.component.scss'] 7 | }) 8 | export class FooterComponent implements OnInit { 9 | 10 | constructor() { } 11 | 12 | ngOnInit() { 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/app/shared/navbar/navbar.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-navbar', 5 | templateUrl: './navbar.component.html', 6 | styleUrls: ['./navbar.component.scss'] 7 | }) 8 | export class NavbarComponent implements OnInit { 9 | 10 | constructor() { } 11 | 12 | ngOnInit() { 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ProyectoBaseAngular 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/app/shared/sidebar/sidebar.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-sidebar', 5 | templateUrl: './sidebar.component.html', 6 | styleUrls: ['./sidebar.component.scss'] 7 | }) 8 | export class SidebarComponent implements OnInit { 9 | 10 | constructor() { } 11 | 12 | ngOnInit() { 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /cypress.json: -------------------------------------------------------------------------------- 1 | { 2 | "fixturesFolder": "./stubs", 3 | "integrationFolder": "./e2e/features", 4 | "pluginsFile": "./e2e/plugins/index.js", 5 | "screenshotsFolder": "./e2e/screenshots", 6 | "supportFile": "./e2e/support/index.ts", 7 | "videosFolder": "./e2e/videos", 8 | "baseUrl": "http://localhost:4200", 9 | "video": false, 10 | "chromeWebSecurity": false 11 | } 12 | -------------------------------------------------------------------------------- /src/app/shared/page-not-found/page-not-found.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-page-not-found', 5 | templateUrl: './page-not-found.component.html', 6 | styleUrls: ['./page-not-found.component.scss'] 7 | }) 8 | export class PageNotFoundComponent implements OnInit { 9 | 10 | constructor() { } 11 | 12 | ngOnInit() { 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/app/views/vista-de-prueba/vista-de-prueba.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-vista-de-prueba', 5 | templateUrl: './vista-de-prueba.component.html', 6 | styleUrls: ['./vista-de-prueba.component.scss'] 7 | }) 8 | export class VistaDePruebaComponent implements OnInit { 9 | 10 | constructor() { } 11 | 12 | ngOnInit() { 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import { enableProdMode } from '@angular/core'; 2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 3 | 4 | import { AppModule } from './app/app.module'; 5 | import { environment } from './environments/environment'; 6 | 7 | if (environment.production) { 8 | enableProdMode(); 9 | } 10 | 11 | platformBrowserDynamic().bootstrapModule(AppModule) 12 | .catch(err => console.error(err)); 13 | -------------------------------------------------------------------------------- /browserslist: -------------------------------------------------------------------------------- 1 | # This file is used by the build system to adjust CSS and JS output to support the specified browsers below. 2 | # For additional information regarding the format and rule options, please see: 3 | # https://github.com/browserslist/browserslist#queries 4 | 5 | # You can see what browsers were selected by your queries by running: 6 | # npx browserslist 7 | 8 | > 0.5% 9 | last 2 versions 10 | Firefox ESR 11 | not dead 12 | not IE 9-11 # For IE 9-11 support, remove 'not'. -------------------------------------------------------------------------------- /src/app/views/vista-de-prueba/vista-de-prueba.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { CommonModule } from '@angular/common'; 3 | import { VistaDePruebaComponent } from './vista-de-prueba.component'; 4 | import { VistaDePruebaRoutingModule } from './vista-de-prueba-routing.module'; 5 | 6 | 7 | 8 | @NgModule({ 9 | declarations: [VistaDePruebaComponent], 10 | imports: [ 11 | CommonModule, 12 | VistaDePruebaRoutingModule 13 | ] 14 | }) 15 | export class VistaDePruebaModule { } 16 | -------------------------------------------------------------------------------- /src/app/views/vista-de-prueba/vista-de-prueba-routing.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { Routes, RouterModule } from '@angular/router'; 3 | import { VistaDePruebaComponent } from './vista-de-prueba.component'; 4 | 5 | const routes: Routes = [ 6 | { 7 | path: 'vista-de-prueba', component: VistaDePruebaComponent 8 | }, 9 | ]; 10 | 11 | @NgModule({ 12 | imports: [RouterModule.forChild(routes)], 13 | exports: [RouterModule] 14 | }) 15 | export class VistaDePruebaRoutingModule { } 16 | -------------------------------------------------------------------------------- /src/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import { BrowserModule } from '@angular/platform-browser'; 2 | import { NgModule } from '@angular/core'; 3 | 4 | import { AppRoutingModule } from './app-routing.module'; 5 | import { AppComponent } from './app.component'; 6 | 7 | // Modulos generales importados 8 | import { SharedModule } from './shared/shared.module'; 9 | 10 | 11 | @NgModule({ 12 | declarations: [ 13 | AppComponent 14 | ], 15 | imports: [ 16 | BrowserModule, 17 | AppRoutingModule, 18 | SharedModule 19 | ], 20 | providers: [], 21 | bootstrap: [AppComponent] 22 | }) 23 | export class AppModule { } 24 | -------------------------------------------------------------------------------- /src/app/shared/shared.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { CommonModule } from '@angular/common'; 3 | import { SidebarComponent } from './sidebar/sidebar.component'; 4 | import { PageNotFoundComponent } from './page-not-found/page-not-found.component'; 5 | import { NavbarComponent } from './navbar/navbar.component'; 6 | import { FooterComponent } from './footer/footer.component'; 7 | 8 | 9 | 10 | @NgModule({ 11 | declarations: [SidebarComponent, PageNotFoundComponent, NavbarComponent, FooterComponent], 12 | imports: [ 13 | CommonModule 14 | ] 15 | }) 16 | export class SharedModule { } 17 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "baseUrl": "./", 5 | "outDir": "./dist/out-tsc", 6 | "sourceMap": true, 7 | "declaration": false, 8 | "downlevelIteration": true, 9 | "experimentalDecorators": true, 10 | "module": "esnext", 11 | "moduleResolution": "node", 12 | "importHelpers": true, 13 | "target": "es2015", 14 | "typeRoots": [ 15 | "node_modules/@types" 16 | ], 17 | "lib": [ 18 | "es2018", 19 | "dom" 20 | ] 21 | }, 22 | "angularCompilerOptions": { 23 | "fullTemplateTypeCheck": true, 24 | "strictInjectionParameters": true 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/test.ts: -------------------------------------------------------------------------------- 1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files 2 | 3 | import 'zone.js/dist/zone-testing'; 4 | import { getTestBed } from '@angular/core/testing'; 5 | import { 6 | BrowserDynamicTestingModule, 7 | platformBrowserDynamicTesting 8 | } from '@angular/platform-browser-dynamic/testing'; 9 | 10 | declare const require: any; 11 | 12 | // First, initialize the Angular testing environment. 13 | getTestBed().initTestEnvironment( 14 | BrowserDynamicTestingModule, 15 | platformBrowserDynamicTesting() 16 | ); 17 | // Then we find all the tests. 18 | const context = require.context('./', true, /\.spec\.ts$/); 19 | // And load the modules. 20 | context.keys().map(context); 21 | -------------------------------------------------------------------------------- /src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // This file can be replaced during build by using the `fileReplacements` array. 2 | // `ng build --prod` replaces `environment.ts` with `environment.prod.ts`. 3 | // The list of file replacements can be found in `angular.json`. 4 | 5 | export const environment = { 6 | production: false 7 | }; 8 | 9 | /* 10 | * For easier debugging in development mode, you can import the following file 11 | * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`. 12 | * 13 | * This import should be commented out in production mode because it will have a negative impact 14 | * on performance if an error is thrown. 15 | */ 16 | // import 'zone.js/dist/zone-error'; // Included with Angular CLI. 17 | -------------------------------------------------------------------------------- /e2e/support/index.ts: -------------------------------------------------------------------------------- 1 | // *********************************************************** 2 | // This example support/index.js is processed and 3 | // loaded automatically before your test files. 4 | // 5 | // This is a great place to put global configuration and 6 | // behavior that modifies Cypress. 7 | // 8 | // You can change the location of this file or turn off 9 | // automatically serving support files with the 10 | // 'supportFile' configuration option. 11 | // 12 | // You can read more here: 13 | // https://on.cypress.io/configuration 14 | // *********************************************************** 15 | 16 | // Import commands.js using ES2015 syntax: 17 | import './commands'; 18 | 19 | // Alternatively you can use CommonJS syntax: 20 | // require('./commands') 21 | -------------------------------------------------------------------------------- /src/app/shared/footer/footer.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { FooterComponent } from './footer.component'; 4 | 5 | describe('FooterComponent', () => { 6 | let component: FooterComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ FooterComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(FooterComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/shared/navbar/navbar.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { NavbarComponent } from './navbar.component'; 4 | 5 | describe('NavbarComponent', () => { 6 | let component: NavbarComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ NavbarComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(NavbarComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /e2e/plugins/webpack.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | resolve: { 3 | extensions: ['.ts', '.js'] 4 | }, 5 | node: { fs: 'empty', child_process: 'empty', readline: 'empty' }, 6 | module: { 7 | rules: [ 8 | { 9 | test: /\.ts$/, 10 | exclude: [/node_modules/], 11 | use: [ 12 | { 13 | loader: 'ts-loader' 14 | } 15 | ] 16 | }, 17 | { 18 | test: /\.feature$/, 19 | use: [ 20 | { 21 | loader: 'cypress-cucumber-preprocessor/loader' 22 | } 23 | ] 24 | } 25 | ] 26 | } 27 | }; 28 | -------------------------------------------------------------------------------- /src/app/shared/sidebar/sidebar.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { SidebarComponent } from './sidebar.component'; 4 | 5 | describe('SidebarComponent', () => { 6 | let component: SidebarComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ SidebarComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(SidebarComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/app-routing.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { Routes, RouterModule } from '@angular/router'; 3 | import { PageNotFoundComponent } from './shared/page-not-found/page-not-found.component'; 4 | 5 | 6 | const routes: Routes = [ 7 | { 8 | path: 'boilerplate', loadChildren: () => 9 | import('./views/vista-de-prueba/vista-de-prueba.module') 10 | .then(mod => mod.VistaDePruebaModule) 11 | }, 12 | { path: '', redirectTo: 'boilerplate/vista-de-prueba', pathMatch: 'full' }, 13 | { path: '**', pathMatch: 'full', component: PageNotFoundComponent }, 14 | ]; 15 | 16 | @NgModule({ 17 | imports: [RouterModule.forRoot(routes)], 18 | exports: [RouterModule] 19 | }) 20 | export class AppRoutingModule { } 21 | -------------------------------------------------------------------------------- /src/app/shared/page-not-found/page-not-found.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { PageNotFoundComponent } from './page-not-found.component'; 4 | 5 | describe('PageNotFoundComponent', () => { 6 | let component: PageNotFoundComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ PageNotFoundComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(PageNotFoundComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/views/vista-de-prueba/vista-de-prueba.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { VistaDePruebaComponent } from './vista-de-prueba.component'; 4 | 5 | describe('VistaDePruebaComponent', () => { 6 | let component: VistaDePruebaComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ VistaDePruebaComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(VistaDePruebaComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /dist 5 | /tmp 6 | /out-tsc 7 | # Only exists if Bazel was run 8 | /bazel-out 9 | 10 | # dependencies 11 | /node_modules 12 | 13 | # profiling files 14 | chrome-profiler-events*.json 15 | speed-measure-plugin*.json 16 | 17 | # IDEs and editors 18 | /.idea 19 | .project 20 | .classpath 21 | .c9/ 22 | *.launch 23 | .settings/ 24 | *.sublime-workspace 25 | 26 | # IDE - VSCode 27 | .vscode/* 28 | !.vscode/settings.json 29 | !.vscode/tasks.json 30 | !.vscode/launch.json 31 | !.vscode/extensions.json 32 | .history/* 33 | 34 | # misc 35 | /.sass-cache 36 | /connect.lock 37 | /coverage 38 | /libpeerconnection.log 39 | npm-debug.log 40 | yarn-error.log 41 | testem.log 42 | /typings 43 | 44 | # System Files 45 | .DS_Store 46 | Thumbs.db 47 | -------------------------------------------------------------------------------- /e2e/step_definitions/home_steps.ts: -------------------------------------------------------------------------------- 1 | // Assume that this 2 | const { Given, When, Then, And } = require('cypress-cucumber-preprocessor/steps'); 3 | 4 | Given('the user visit the main page', () => { 5 | cy.visit('http://localhost:4200/'); 6 | }); 7 | 8 | Then('page should have the right title', () => { 9 | cy.getPackageName() 10 | .then((packageName: any ) => { 11 | // Angular converts a dashed-name on package.json to Capitalize and Camel case 12 | // format for the title 13 | const pageTitle = packageName 14 | .replace(/-([a-z])/g, (match: any, character: string) => character.toUpperCase()) 15 | .replace(/^([a-z])/g, (match: any, character: string) => character.toUpperCase()); 16 | cy.title().should('contains', pageTitle); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /e2e/support/commands.ts: -------------------------------------------------------------------------------- 1 | const packageJson = require('../../package.json'); 2 | 3 | /** 4 | * Navigates to page with pageName 5 | */ 6 | Cypress.Commands.add('navigate', (pageName) => { 7 | // Find navigation menu item 8 | // Click on it 9 | cy.visit(`/${pageName}`); 10 | }); 11 | 12 | Cypress.Commands.add('getPackageName', () => packageJson.name); 13 | 14 | // Must be declared global to be detected by typescript (allows import/export) 15 | // tslint:disable-next-line:no-namespace 16 | declare global { 17 | namespace Cypress { 18 | // tslint:disable-next-line:interface-name 19 | interface Chainable { 20 | navigate(pageName: string): void; 21 | getPackageName(): Chainable; 22 | } 23 | } 24 | } 25 | 26 | // Convert this to a module instead of script (allows import/export) 27 | export { }; 28 | -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration file, see link for more information 2 | // https://karma-runner.github.io/1.0/config/configuration-file.html 3 | 4 | module.exports = function (config) { 5 | config.set({ 6 | basePath: '', 7 | frameworks: ['jasmine', '@angular-devkit/build-angular'], 8 | plugins: [ 9 | require('karma-jasmine'), 10 | require('karma-chrome-launcher'), 11 | require('karma-jasmine-html-reporter'), 12 | require('karma-coverage-istanbul-reporter'), 13 | require('@angular-devkit/build-angular/plugins/karma') 14 | ], 15 | client: { 16 | clearContext: false // leave Jasmine Spec Runner output visible in browser 17 | }, 18 | coverageIstanbulReporter: { 19 | dir: require('path').join(__dirname, './coverage/proyecto-base-angular'), 20 | reports: ['html', 'lcovonly', 'text-summary'], 21 | fixWebpackSourcePaths: true 22 | }, 23 | reporters: ['progress', 'kjhtml'], 24 | port: 9876, 25 | colors: true, 26 | logLevel: config.LOG_INFO, 27 | autoWatch: true, 28 | browsers: ['Chrome'], 29 | singleRun: false, 30 | restartOnFileChange: true 31 | }); 32 | }; 33 | -------------------------------------------------------------------------------- /src/app/app.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, async } from '@angular/core/testing'; 2 | import { RouterTestingModule } from '@angular/router/testing'; 3 | import { AppComponent } from './app.component'; 4 | 5 | describe('AppComponent', () => { 6 | beforeEach(async(() => { 7 | TestBed.configureTestingModule({ 8 | imports: [ 9 | RouterTestingModule 10 | ], 11 | declarations: [ 12 | AppComponent 13 | ], 14 | }).compileComponents(); 15 | })); 16 | 17 | it('should create the app', () => { 18 | const fixture = TestBed.createComponent(AppComponent); 19 | const app = fixture.debugElement.componentInstance; 20 | expect(app).toBeTruthy(); 21 | }); 22 | 23 | it(`should have as title 'proyecto-base-angular'`, () => { 24 | const fixture = TestBed.createComponent(AppComponent); 25 | const app = fixture.debugElement.componentInstance; 26 | expect(app.title).toEqual('proyecto-base-angular'); 27 | }); 28 | 29 | it('should render title', () => { 30 | const fixture = TestBed.createComponent(AppComponent); 31 | fixture.detectChanges(); 32 | const compiled = fixture.debugElement.nativeElement; 33 | expect(compiled.querySelector('.content span').textContent).toContain('proyecto-base-angular app is running!'); 34 | }); 35 | }); 36 | -------------------------------------------------------------------------------- /src/app/views/vista-de-prueba/vista-de-prueba.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 | 11 | 17 | 23 | 29 |
30 |
-------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "proyecto-base-angular", 3 | "version": "0.0.0", 4 | "scripts": { 5 | "ng": "ng", 6 | "start": "ng serve", 7 | "build": "ng build", 8 | "test": "ng test", 9 | "lint": "ng lint", 10 | "e2e": "ng e2e", 11 | "e2e:ci": "ng e2e --mode console" 12 | }, 13 | "private": true, 14 | "dependencies": { 15 | "@angular/animations": "~9.1.2", 16 | "@angular/common": "~9.1.2", 17 | "@angular/compiler": "~9.1.2", 18 | "@angular/core": "~9.1.2", 19 | "@angular/forms": "~9.1.2", 20 | "@angular/platform-browser": "~9.1.2", 21 | "@angular/platform-browser-dynamic": "~9.1.2", 22 | "@angular/router": "~9.1.2", 23 | "@ngchile/cypress-cucumber-schematics": "^1.0.0-rc.5", 24 | "bootstrap": "^4.4.1", 25 | "jquery": "^3.5.0", 26 | "moment": "^2.24.0", 27 | "ngx-bootstrap": "^5.6.1", 28 | "rxjs": "~6.5.5", 29 | "tslib": "^1.10.0", 30 | "zone.js": "~0.10.2" 31 | }, 32 | "devDependencies": { 33 | "@angular-devkit/build-angular": "~0.901.1", 34 | "@angular/cli": "~9.1.1", 35 | "@angular/compiler-cli": "~9.1.2", 36 | "@angular/language-service": "~9.1.2", 37 | "@cypress/webpack-preprocessor": "5.1.2", 38 | "@types/node": "^12.11.1", 39 | "@types/jasmine": "~3.3.8", 40 | "@types/jasminewd2": "~2.0.3", 41 | "codelyzer": "^5.1.2", 42 | "cypress-cucumber-preprocessor": "2.3.0", 43 | "jasmine-core": "~3.4.0", 44 | "jasmine-spec-reporter": "~4.2.1", 45 | "karma": "~4.1.0", 46 | "karma-chrome-launcher": "~2.2.0", 47 | "karma-coverage-istanbul-reporter": "~2.0.1", 48 | "karma-jasmine": "~2.0.1", 49 | "karma-jasmine-html-reporter": "^1.4.0", 50 | "protractor": "~5.4.0", 51 | "ts-loader": "7.0.0", 52 | "ts-node": "~7.0.0", 53 | "tslint": "~5.15.0", 54 | "typescript": "~3.8.3" 55 | }, 56 | "cypress-cucumber-preprocessor": { 57 | "step_definitions": "./e2e/step_definitions" 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "tslint:recommended", 3 | "rules": { 4 | "array-type": false, 5 | "arrow-parens": false, 6 | "deprecation": { 7 | "severity": "warning" 8 | }, 9 | "component-class-suffix": true, 10 | "contextual-lifecycle": true, 11 | "directive-class-suffix": true, 12 | "directive-selector": [ 13 | true, 14 | "attribute", 15 | "app", 16 | "camelCase" 17 | ], 18 | "component-selector": [ 19 | true, 20 | "element", 21 | "app", 22 | "kebab-case" 23 | ], 24 | "import-blacklist": [ 25 | true, 26 | "rxjs/Rx" 27 | ], 28 | "interface-name": false, 29 | "max-classes-per-file": false, 30 | "max-line-length": [ 31 | true, 32 | 140 33 | ], 34 | "member-access": false, 35 | "member-ordering": [ 36 | true, 37 | { 38 | "order": [ 39 | "static-field", 40 | "instance-field", 41 | "static-method", 42 | "instance-method" 43 | ] 44 | } 45 | ], 46 | "no-consecutive-blank-lines": false, 47 | "no-console": [ 48 | true, 49 | "debug", 50 | "info", 51 | "time", 52 | "timeEnd", 53 | "trace" 54 | ], 55 | "no-empty": false, 56 | "no-inferrable-types": [ 57 | true, 58 | "ignore-params" 59 | ], 60 | "no-non-null-assertion": true, 61 | "no-redundant-jsdoc": true, 62 | "no-switch-case-fall-through": true, 63 | "no-use-before-declare": true, 64 | "no-var-requires": false, 65 | "object-literal-key-quotes": [ 66 | true, 67 | "as-needed" 68 | ], 69 | "object-literal-sort-keys": false, 70 | "ordered-imports": false, 71 | "quotemark": [ 72 | true, 73 | "single" 74 | ], 75 | "trailing-comma": false, 76 | "no-conflicting-lifecycle": true, 77 | "no-host-metadata-property": true, 78 | "no-input-rename": true, 79 | "no-inputs-metadata-property": true, 80 | "no-output-native": true, 81 | "no-output-on-prefix": true, 82 | "no-output-rename": true, 83 | "no-outputs-metadata-property": true, 84 | "template-banana-in-box": true, 85 | "template-no-negated-async": true, 86 | "use-lifecycle-interface": true, 87 | "use-pipe-transform-interface": true 88 | }, 89 | "rulesDirectory": [ 90 | "codelyzer" 91 | ] 92 | } -------------------------------------------------------------------------------- /src/app/views/vista-de-prueba/vista-de-prueba.component.scss: -------------------------------------------------------------------------------- 1 | @import url(//maxcdn.bootstrapcdn.com/font-awesome/4.6.3/css/font-awesome.min.css); 2 | .kpx_social .kpx_authTitle { 3 | text-align: center; 4 | line-height: 300%; 5 | } 6 | 7 | .kpx_social .kpx_socialButtons a { 8 | color: white; 9 | opacity: 0.9; 10 | } 11 | 12 | .kpx_social .kpx_socialButtons a:hover { 13 | color: white; 14 | opacity: 1; 15 | } 16 | 17 | .kpx_social .kpx_socialButtons .kpx_btn-facebook { 18 | background: #3b5998; 19 | -webkit-transition: all 0.5s ease-in-out; 20 | -moz-transition: all 0.5s ease-in-out; 21 | -o-transition: all 0.5s ease-in-out; 22 | transition: all 0.5s ease-in-out; 23 | } 24 | 25 | .kpx_social .kpx_socialButtons .kpx_btn-facebook:hover { 26 | background: #172d5e 27 | } 28 | 29 | .kpx_social .kpx_socialButtons .kpx_btn-facebook:focus { 30 | background: #fff; 31 | color: #3b5998; 32 | border-color: #3b5998; 33 | } 34 | 35 | .kpx_social .kpx_socialButtons .kpx_btn-github { 36 | background: #666666; 37 | -webkit-transition: all 0.5s ease-in-out; 38 | -moz-transition: all 0.5s ease-in-out; 39 | -o-transition: all 0.5s ease-in-out; 40 | transition: all 0.5s ease-in-out; 41 | } 42 | 43 | .kpx_social .kpx_socialButtons .kpx_btn-github:hover { 44 | background: #333333 45 | } 46 | 47 | .kpx_social .kpx_socialButtons .kpx_btn-github:focus { 48 | background: #fff; 49 | color: #666666; 50 | border-color: #666666 51 | } 52 | 53 | .kpx_social .kpx_socialButtons .kpx_btn-linkedin { 54 | background: #0976b4; 55 | -webkit-transition: all 0.5s ease-in-out; 56 | -moz-transition: all 0.5s ease-in-out; 57 | -o-transition: all 0.5s ease-in-out; 58 | transition: all 0.5s ease-in-out; 59 | } 60 | 61 | .kpx_social .kpx_socialButtons .kpx_btn-linkedin:hover { 62 | background: #004269 63 | } 64 | 65 | .kpx_social .kpx_socialButtons .kpx_btn-linkedin:focus { 66 | background: #fff; 67 | color: #0976b4; 68 | border-color: #0976b4 69 | } 70 | 71 | .kpx_social .kpx_socialButtons .kpx_btn-medium { 72 | background: #000; 73 | -webkit-transition: all 0.5s ease-in-out; 74 | -moz-transition: all 0.5s ease-in-out; 75 | -o-transition: all 0.5s ease-in-out; 76 | transition: all 0.5s ease-in-out; 77 | font-weight: bold; 78 | font-size: 1.7em; 79 | } 80 | 81 | .kpx_social .kpx_socialButtons .kpx_btn-medium:hover { 82 | background: #000 83 | } 84 | 85 | .kpx_social .kpx_socialButtons .kpx_btn-medium:focus { 86 | background: #fff; 87 | color: #0976b4; 88 | border-color: #0976b4 89 | } -------------------------------------------------------------------------------- /src/polyfills.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file includes polyfills needed by Angular and is loaded before the app. 3 | * You can add your own extra polyfills to this file. 4 | * 5 | * This file is divided into 2 sections: 6 | * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. 7 | * 2. Application imports. Files imported after ZoneJS that should be loaded before your main 8 | * file. 9 | * 10 | * The current setup is for so-called "evergreen" browsers; the last versions of browsers that 11 | * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera), 12 | * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile. 13 | * 14 | * Learn more in https://angular.io/guide/browser-support 15 | */ 16 | 17 | /*************************************************************************************************** 18 | * BROWSER POLYFILLS 19 | */ 20 | 21 | /** IE10 and IE11 requires the following for NgClass support on SVG elements */ 22 | // import 'classlist.js'; // Run `npm install --save classlist.js`. 23 | 24 | /** 25 | * Web Animations `@angular/platform-browser/animations` 26 | * Only required if AnimationBuilder is used within the application and using IE/Edge or Safari. 27 | * Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0). 28 | */ 29 | // import 'web-animations-js'; // Run `npm install --save web-animations-js`. 30 | 31 | /** 32 | * By default, zone.js will patch all possible macroTask and DomEvents 33 | * user can disable parts of macroTask/DomEvents patch by setting following flags 34 | * because those flags need to be set before `zone.js` being loaded, and webpack 35 | * will put import in the top of bundle, so user need to create a separate file 36 | * in this directory (for example: zone-flags.ts), and put the following flags 37 | * into that file, and then add the following code before importing zone.js. 38 | * import './zone-flags.ts'; 39 | * 40 | * The flags allowed in zone-flags.ts are listed here. 41 | * 42 | * The following flags will work for all browsers. 43 | * 44 | * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame 45 | * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick 46 | * (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames 47 | * 48 | * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js 49 | * with the following flag, it will bypass `zone.js` patch for IE/Edge 50 | * 51 | * (window as any).__Zone_enable_cross_context_check = true; 52 | * 53 | */ 54 | 55 | /*************************************************************************************************** 56 | * Zone JS is required by default for Angular itself. 57 | */ 58 | import 'zone.js/dist/zone'; // Included with Angular CLI. 59 | 60 | 61 | /*************************************************************************************************** 62 | * APPLICATION IMPORTS 63 | */ 64 | -------------------------------------------------------------------------------- /angular.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json", 3 | "version": 1, 4 | "newProjectRoot": "projects", 5 | "projects": { 6 | "proyecto-base-angular": { 7 | "projectType": "application", 8 | "schematics": { 9 | "@schematics/angular:component": { 10 | "style": "scss" 11 | } 12 | }, 13 | "root": "", 14 | "sourceRoot": "src", 15 | "prefix": "app", 16 | "architect": { 17 | "build": { 18 | "builder": "@angular-devkit/build-angular:browser", 19 | "options": { 20 | "outputPath": "dist/proyecto-base-angular", 21 | "index": "src/index.html", 22 | "main": "src/main.ts", 23 | "polyfills": "src/polyfills.ts", 24 | "tsConfig": "tsconfig.app.json", 25 | "aot": true, 26 | "assets": [ 27 | "src/favicon.ico", 28 | "src/assets" 29 | ], 30 | "styles": [ 31 | "src/styles.scss", 32 | "node_modules/bootstrap/dist/css/bootstrap.min.css" 33 | ], 34 | "scripts": [ 35 | "node_modules/jquery/dist/jquery.slim.min.js", 36 | "node_modules/bootstrap/dist/js/bootstrap.min.js" 37 | ] 38 | }, 39 | "configurations": { 40 | "production": { 41 | "fileReplacements": [ 42 | { 43 | "replace": "src/environments/environment.ts", 44 | "with": "src/environments/environment.prod.ts" 45 | } 46 | ], 47 | "optimization": true, 48 | "outputHashing": "all", 49 | "sourceMap": false, 50 | "extractCss": true, 51 | "namedChunks": false, 52 | "extractLicenses": true, 53 | "vendorChunk": false, 54 | "buildOptimizer": true, 55 | "budgets": [ 56 | { 57 | "type": "initial", 58 | "maximumWarning": "2mb", 59 | "maximumError": "5mb" 60 | }, 61 | { 62 | "type": "anyComponentStyle", 63 | "maximumWarning": "6kb", 64 | "maximumError": "10kb" 65 | } 66 | ] 67 | } 68 | } 69 | }, 70 | "serve": { 71 | "builder": "@angular-devkit/build-angular:dev-server", 72 | "options": { 73 | "browserTarget": "proyecto-base-angular:build" 74 | }, 75 | "configurations": { 76 | "production": { 77 | "browserTarget": "proyecto-base-angular:build:production" 78 | } 79 | } 80 | }, 81 | "extract-i18n": { 82 | "builder": "@angular-devkit/build-angular:extract-i18n", 83 | "options": { 84 | "browserTarget": "proyecto-base-angular:build" 85 | } 86 | }, 87 | "test": { 88 | "builder": "@angular-devkit/build-angular:karma", 89 | "options": { 90 | "main": "src/test.ts", 91 | "polyfills": "src/polyfills.ts", 92 | "tsConfig": "tsconfig.spec.json", 93 | "karmaConfig": "karma.conf.js", 94 | "assets": [ 95 | "src/favicon.ico", 96 | "src/assets" 97 | ], 98 | "styles": [ 99 | "src/styles.scss" 100 | ], 101 | "scripts": [] 102 | } 103 | }, 104 | "lint": { 105 | "builder": "@angular-devkit/build-angular:tslint", 106 | "options": { 107 | "tsConfig": [ 108 | "tsconfig.app.json", 109 | "tsconfig.spec.json", 110 | "e2e/tsconfig.json" 111 | ], 112 | "exclude": [ 113 | "**/node_modules/**" 114 | ] 115 | } 116 | }, 117 | "e2e": { 118 | "builder": "@ngchile/cypress-cucumber-schematics:cypress", 119 | "options": { 120 | "devServerTarget": "proyecto-base-angular:serve", 121 | "mode": "browser" 122 | }, 123 | "configurations": { 124 | "production": { 125 | "devServerTarget": "proyecto-base-angular:serve:production" 126 | } 127 | } 128 | } 129 | } 130 | } 131 | }, 132 | "defaultProject": "proyecto-base-angular", 133 | "cli": { 134 | "analytics": "6a9eca3e-e3a8-4c0c-87cd-766a26bd7dae" 135 | } 136 | } -------------------------------------------------------------------------------- /e2e/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Basic Options */ 4 | "target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */ 5 | "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ 6 | // "lib": ["es5", "dom"], /* Specify library files to be included in the compilation. */ 7 | // "allowJs": true, /* Allow javascript files to be compiled. */ 8 | // "checkJs": true, /* Report errors in .js files. */ 9 | // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ 10 | // "declaration": true, /* Generates corresponding '.d.ts' file. */ 11 | // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ 12 | // "sourceMap": true, /* Generates corresponding '.map' file. */ 13 | // "outFile": "./", /* Concatenate and emit output to single file. */ 14 | // "outDir": "./", /* Redirect output structure to the directory. */ 15 | // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ 16 | // "composite": true, /* Enable project compilation */ 17 | // "removeComments": true, /* Do not emit comments to output. */ 18 | // "noEmit": true, /* Do not emit outputs. */ 19 | // "importHelpers": true, /* Import emit helpers from 'tslib'. */ 20 | // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ 21 | // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ 22 | 23 | /* Strict Type-Checking Options */ 24 | "strict": true, /* Enable all strict type-checking options. */ 25 | // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ 26 | // "strictNullChecks": true, /* Enable strict null checks. */ 27 | // "strictFunctionTypes": true, /* Enable strict checking of function types. */ 28 | // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ 29 | // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ 30 | // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ 31 | // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ 32 | 33 | /* Additional Checks */ 34 | // "noUnusedLocals": true, /* Report errors on unused locals. */ 35 | // "noUnusedParameters": true, /* Report errors on unused parameters. */ 36 | // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ 37 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ 38 | 39 | /* Module Resolution Options */ 40 | // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ 41 | "baseUrl": "../node_modules", /* Base directory to resolve non-absolute module names. */ 42 | // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ 43 | // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ 44 | "typeRoots": ["node_modules/@types"], /* List of folders to include type definitions from. */ 45 | "types": ["cypress", "node"], /* Type declaration files to be included in compilation. */ 46 | // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ 47 | "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ 48 | // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ 49 | 50 | /* Source Map Options */ 51 | // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ 52 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ 53 | // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ 54 | // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ 55 | 56 | /* Experimental Options */ 57 | // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ 58 | // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ 59 | }, 60 | "include": ["**/*.ts"] 61 | } 62 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Boilerplate Angular 2 | 3 | Proyecto que contiene el esqueleto base que se debe utilizar de ahora en adelante por la parte FRONTEND, esta estructurado y armado con el Framework Angular v8.3 (https://angular.io/) integrado con el framework de estilos Bootstrap 4. 4 | 5 | # Instalaciones necesarias 6 | 7 | 1. Instalar NODE js: https://nodejs.org/es/ 8 | 2. Instalar GIT: https://git-scm.com/ 9 | 3. Instalar Typescript: https://www.typescriptlang.org/ 10 | 4. Instalar Angular CLI: https://cli.angular.io/ 11 | 12 | # Levantar proyecto 13 | 14 | 1. Clona el repositorio `git clone https://github.com/fbellod1986/boilerplate-angular-base.git` 15 | 2. Ejecuta `ng update @angular/core @angular/cli --force` para actualizar a la ultima version de angular. Con respecto a esto, cualquier duda ver sitio [Angular Update Guide](https://update.angular.io/) 16 | 2. Ejecuta `npm install` para instalar todas las dependencias necesarias para que la aplicación pueda levantarse. 17 | 3. Ejecuta `ng serve` en la consola. Navega a `http://localhost:4200/`. La aplicación se volverá a cargar automáticamente si cambia alguno de los archivos de origen. 18 | 19 | 20 | # Links de interés hechos por [Franco Bello](https://medium.com/@fbellod) 21 | 22 | Integración continua: Angular + Github + Firebase + Travis CI: 23 | https://medium.com/angular-chile/integraci%C3%B3n-continua-angular-github-firebase-travis-ci-a1a8946d471a 24 | 25 | Entendiendo el LazyLoad y sus beneficios + ANGULAR 26 | https://medium.com/@fbellod/entendiendo-el-lazyload-y-sus-beneficios-angular-b8ae4bffa199 27 | 28 | Como iterar y subir los cambios de tu APP con Angular a Firebase: https://medium.com/front-end-chile/como-iterar-y-subir-los-cambios-de-tu-app-con-angular-a-firebase-658d07d766c7 29 | 30 | Firebase: Como subir tu APP de Angular a Firebase. 31 | https://medium.com/front-end-chile/firebase-como-subir-tu-app-de-angular-a-firebase-93de35ff9f09 32 | 33 | Como Integrar el Framework Bootstrap en un proyecto Angular: 34 | https://medium.com/@fbellod/como-integrar-el-framework-bootstrap-en-un-proyecto-angular-a5d53fa79e03 35 | 36 | Como consultar la “foto del día” directo desde la Nasa con Angular y Bootstrap 4: 37 | https://medium.com/@fbellod/como-consultar-la-foto-del-d%C3%ADa-directo-desde-la-nasa-con-angular-y-bootstrap-4-513fb1bdc9c5 38 | 39 | Como setear valores en la cabecera desde el route params con Interceptors + ANGULAR: 40 | https://medium.com/@fbellod/como-setear-valores-en-la-cabecera-desde-el-route-params-con-interceptors-angular-1b2d025bebb1 41 | 42 | 43 | # Dependencias instaladas 44 | 45 | ## CYPRESS 46 | * [Cypress](https://fotos.subefotos.com/ef4b8a0e1b5c946e888b26eb8a828f8ao.png) 47 | 48 | ![](https://fotos.subefotos.com/ef4b8a0e1b5c946e888b26eb8a828f8ao.png) 49 | 50 | ## Interacciones 51 | * [NGX Bootstrap](https://valor-software.com/ngx-bootstrap/) 52 | 53 | ## Framework de estilos 54 | * [Bootstrap](https://getbootstrap.com/) 55 | 56 | ## Fechas y Horas 57 | * [Moments](https://momentjs.com/) 58 | 59 | # Buenas practicas 60 | 61 | ## Estructura de archivos 62 | Generalmente se define la estructura de acuerdo a la complejidad del proyecto. Entre más grande sea, mas orden requiere. Este es un ejemplo de un proyecto en el cual se separaron los componentes. El folder Auth representa todos los componentes relacionados con el login y registro de un sitio. A la misma altura se crearon los demás componentes. Así mismo, hay una carpeta Shared, que contiene archivos que se usarán de forma global, como lo son los services, models, helpers, footer, header, y demás componentes que puedas requerir. 63 | 64 | El nivel de complejidad de la aplicación va a requerir mejor organización. Tener una estructura bien definida nos ayudará a pensar en escalabilidad. 65 | 66 | ![](https://fotos.subefotos.com/1e72226c61c3e7346e6a378f38a0a098o.png) 67 | 68 | ## Nombres claros 69 | Uno de los mayores problemas a la hora de entender el código, suele ser el nombre que le damos a nuestros métodos, variables o parámetros. 70 | 71 | #### Esto 72 | ![](https://miro.medium.com/max/268/1*zEP_U4K2QKX0ypveH8IqcQ.png) 73 | #### no es lo mismo que esto: 74 | ![](https://miro.medium.com/max/332/1*kuiod_KbJbxaie70gzRIvQ.png) 75 | 76 | ## Organiza tu código 77 | Algunas formas de tener un archivo de código mas organizado y legible son: 78 | 79 | * Lo más importante debe ir arriba. 80 | * Primero propiedades, después métodos. 81 | * Un Item para un archivo: cada archivo debería contener solamente un componente, al igual que los servicios. 82 | * Solo una responsabilidad: Cada clase o modulo debería tener solamente una responsabilidad. 83 | * El nombre correcto: las propiedades y métodos deberían usar el sistema de camel case (ej: getUserByName), al contrario, las clases (componentes, servicios, etc) deben usar upper camel case (ej: UserComponent). 84 | * Los componentes y servicios deben tener su respectivo sufijo: UserComponent, UserService. 85 | * Imports: los archivos externos van primero. 86 | 87 | ## Provee claridad 88 | Cuando estés escribiendo, piensa que probablemente alguien más tendrá que leer tu código en algún momento. Todos hemos sufrido a la hora de leer código ajeno. Es por eso que lo ideal cuando escribimos es pensar en la persona que lo leerá, o incluso en ti mismo. No has llegado a algún trozo de código que tu mismo escribiste pero ni a palos entiendes? 89 | 90 | ## Código auto-descriptivo: 91 | Explica en tu mismo código, no en comentarios. 92 | Tus comentarios deben ser claros y entendibles. 93 | 94 | ## Evita comentar si: 95 | 96 | * Tratas de explicar que hace tu código, deja que este sea tan claro que se explique solo. 97 | * Tienes funciones y métodos bien nombrados. No te llenes de obviedades. 98 | 99 | ## Comenta cuando: 100 | * Trates de explicar por qué hiciste lo que hiciste. 101 | * Trates de explicar consecuencias de lo que escribiste. 3. en API docs. 102 | 103 | ## Componentes 104 | En Angular, lo más importante debe ir al inicio. En nuestros componentes generalmente escribimos nuestras propiedades primero y después nuestros métodos. Así mismo, a veces agrupamos nuestras propiedades o funciones alfabéticamente y otras veces por funcionalidad. Lo importante aquí es mantener una consistencia durante todo el proyecto. 105 | 106 | Además: 107 | Es importante tratar de escribir código lo mas compacto posible. Cada quien tiene una forma distinta de escribir y estructurar sus funciones. A mi gusto, un método no debería tener más de 20 lineas de código, entre más código junto tengas más difícil será entenderlo. Es por esto que utilizamos funciones que nos permitan hacer composición. 108 | Queremos que nuestros componentes sean lo más simples posibles. En este contexto, delega la mayor parte de tu lógica a tus servicios. 109 | Se consistente con tus funciones, y por favor no escribas cosas fuera de lugar!!! Nombrar tu función como “quieroPanConPalta” y cometer faltas ortográficas es una falta de respeto. 110 | 111 | ## Servicios 112 | Algunas de las mejores prácticas a la hora de crear servicios son: 113 | 114 | * Crea tus servicios como Injectables 115 | * Utiliza tus servicios para recolectar tu data: es total responsabilidad de tus servicios recolectar la data necesaria, ya sea desde una API, localstorage o alguna estructura que hayamos creado nosotros mismos para poder desarrollar. 116 | * Tus componentes nunca deben encargarse de pensar como traer data, estos solo deberían encargarse de llamar al servicio que contiene todo lo necesario. Así que por favor, no llames tus API’s en tus componentes. 117 | * Crea un servicio base en la raiz para que sea heredado desde otros servicios que se encuentren en tus modulos. 118 | 119 | ![](https://fotos.subefotos.com/cc1103bcd837d911d9f806a814f48022o.png) 120 | 121 | ## Funcionamiento 122 | Para mejorar el funcionamiento de tus aplicaciones te recomiendo seguir guías de mejores prácticas que se ajusten a tu metodología de trabajo, utilizar compilación AoT (Ahead of Time), agregar lazy loading a tu proyecto, fijarte en el tamaño de tus boundle y de ser posible hacer mejoras utilizando Audits y Lightouse. Pensar con buenas prácticas en el presente te ahorrarán tiempo y dolores de cabeza en el futuro. 123 | 124 | ## Lifecycle Method (Metodo de Ciclo de Vida) 125 | En Angular, cada componente tiene un ciclo de vida, una cantidad de etapas diferentes que atraviesa. Hay 8 etapas diferentes en el ciclo de vida de los componentes. Cada etapa se denomina lifecycle hook event o en ‘evento de enlace de ciclo de vida’. Podemos utilizar estos eventos en diferentes fases de nuestra aplicación para obtener el control de los componentes. Como un componente es una clase de TypeScript, cada componente debe tener un método constructor. 126 | El constructor de la clase de componente se ejecuta primero, antes de la ejecución de cualquier otro lifecycle hook. Si necesitamos inyectar dependencias en el componente, el constructor es el mejor lugar para hacerlo. Después de ejecutar el constructor, Angular ejecuta sus métodos de enganche de ciclo de vida en un orden específico. 127 | ![](https://miro.medium.com/max/842/0*wEGNC-p9kA91tb8K.png) 128 | 129 | 1. `ngOnChanges`: Este evento se ejecuta cada vez que se cambia un valor de un input control dentro de un componente. Se activa primero cuando se cambia el valor de una propiedad vinculada. Siempre recibe un change data map o mapa de datos de cambio, que contiene el valor actual y anterior de la propiedad vinculada envuelta en un SimpleChange 130 | 2. `ngOnInit`: Se ejecuta una vez que Angular ha desplegado los data-bound properties(variables vinculadas a datos) o cuando el componente ha sido inicializado, una vez que ngOnChanges se haya ejecutado. Este evento es utilizado principalmente para inicializar la data en el componente. 131 | 3. `ngDoCheck`: Se activa cada vez que se verifican las propiedades de entrada de un componente. Este método nos permite implementar nuestra propia lógica o algoritmo de detección de cambios personalizado para cualquier componente. 132 | 4. `ngAfterContentInit`: Se ejecuta cuando Angular realiza cualquier muestra de contenido dentro de las vistas de componentes y justo después de ngDoCheck. Actuando una vez que todas las vinculaciones del componente deban verificarse por primera vez. Está vinculado con las inicializaciones del componente hijo. 133 | 5. `ngAfterContentChecked`: Se ejecuta cada vez que el contenido del componente ha sido verificado por el mecanismo de detección de cambios de Angular; se llama después del método ngAfterContentInit. Este también se invoca en cada ejecución posterior de ngDoCheck y está relacionado principalmente con las inicializaciones del componente hijo. 134 | 6. `ngAfterViewInit`: Se ejecuta cuando la vista del componente se ha inicializado por completo. Este método se inicializa después de que Angular ha inicializado la vista del componente y las vistas secundarias. Se llama después de ngAfterContentChecked. Solo se aplica a los componentes. 135 | 7. `ngAfterViewChecked`: Se ejecuta después del método ngAfterViewInit y cada vez que la vista del componente verifique cambios. También se ejecuta cuando se ha modificado cualquier enlace de las directivas secundarias. Por lo tanto, es muy útil cuando el componente espera algún valor que proviene de sus componentes secundarios. 136 | 8. `ngOnDestroy`: Este método se ejecutará justo antes de que Angular destruya los componentes. Es muy útil para darse de baja de los observables y desconectar los event handlers para evitar memory leaks o fugas de memoria. 137 | 138 | Un ejemplo de esta estructura se encuentra en el componente `/boilerplate/life-cycle-method` 139 | 140 | # CanActivate con AuthGuard 141 | Interfaz que una clase puede implementar para ser un guardia que decide si se puede activar una ruta. Si todos los guardias devuelven verdadero, la navegación continuará. Si algún guardia devuelve falso, se cancelará la navegación. Si algún guardia devuelve un UrlTree, se cancelará la navegación actual y se iniciará una nueva navegación hacia el UrlTree que devuelve el guardia. 142 | 143 | 1. Imaginemos que el usuario que se logeo cargo al localStorage un arreglo con solo 2 accesos, estos estan dentro de un objeto llamado scope.role, este objeto vendra del JWT ya desencryptado: 144 | `scope = { 145 | role: ['view-data', 'view-transaction'] 146 | };` 147 | 2. A todos los routing de los componentes se le setea un `expectedRole`, si este coincide con alguna de las opciones del objeto json que se guardo en el localStorage asociado al usuario, se podra acceder a el, de lo contrario retornara false y no mostrara el componente. 148 | ![](https://fotos.subefotos.com/0480c2c25a44cb72a44e010fab7c44b2o.png) 149 | 150 | ## Parte de la información fue sacada gracias a: 151 | https://medium.com/@tatymolys 152 | --------------------------------------------------------------------------------