├── .editorconfig ├── .gitignore ├── README.md ├── angular-cli-build.js ├── angular-cli.json ├── config ├── environment.dev.ts ├── environment.js ├── environment.prod.ts ├── karma-test-shim.js ├── karma.conf.js └── protractor.conf.js ├── e2e ├── app.e2e-spec.ts ├── app.po.ts ├── tsconfig.json └── typings.d.ts ├── package.json ├── public └── .npmignore ├── src ├── app │ ├── app.component.css │ ├── app.component.html │ ├── app.component.spec.ts │ ├── app.component.ts │ ├── app.module.ts │ ├── app.routing.ts │ ├── chapter.service.ts │ ├── chapters-master │ │ ├── chapters-master.component.css │ │ ├── chapters-master.component.html │ │ ├── chapters-master.component.ts │ │ └── index.ts │ ├── db │ │ ├── chapter-members.ts │ │ ├── chapters.ts │ │ ├── defense-measures.ts │ │ ├── guilds.ts │ │ ├── people.ts │ │ └── version.ts │ ├── domain │ │ ├── chapter-location.ts │ │ ├── chapter-member.ts │ │ ├── chapter.ts │ │ ├── customer.ts │ │ ├── guild.ts │ │ ├── http-response.ts │ │ ├── location.ts │ │ └── person.ts │ ├── environment.ts │ ├── guild.service.ts │ ├── guilds-detail │ │ ├── guilds-detail.component.css │ │ ├── guilds-detail.component.html │ │ ├── guilds-detail.component.ts │ │ └── index.ts │ ├── guilds-master │ │ ├── guilds-master.component.css │ │ ├── guilds-master.component.html │ │ ├── guilds-master.component.ts │ │ └── index.ts │ ├── home │ │ ├── home.component.css │ │ ├── home.component.html │ │ ├── home.component.ts │ │ └── index.ts │ ├── in-memory-data.service.ts │ ├── index.ts │ ├── main-navigation │ │ ├── index.ts │ │ ├── main-navigation.component.css │ │ ├── main-navigation.component.html │ │ ├── main-navigation.component.spec.ts │ │ └── main-navigation.component.ts │ ├── member.service.ts │ ├── members-master │ │ ├── index.ts │ │ ├── members-master.component.css │ │ ├── members-master.component.html │ │ └── members-master.component.ts │ ├── sandbox │ │ ├── chapter-list │ │ │ ├── chapter-list.component.css │ │ │ ├── chapter-list.component.html │ │ │ ├── chapter-list.component.ts │ │ │ └── index.ts │ │ ├── chapter-member-list │ │ │ ├── chapter-member-list.component.css │ │ │ ├── chapter-member-list.component.html │ │ │ ├── chapter-member-list.component.ts │ │ │ └── index.ts │ │ ├── chapter-reactive-form │ │ │ ├── chapter-reactive-form.component.css │ │ │ ├── chapter-reactive-form.component.html │ │ │ ├── chapter-reactive-form.component.ts │ │ │ └── index.ts │ │ ├── guild-list │ │ │ ├── guild-list.component.css │ │ │ ├── guild-list.component.html │ │ │ ├── guild-list.component.ts │ │ │ └── index.ts │ │ ├── sandbox.module.ts │ │ ├── sandbox.routing.ts │ │ └── sandbox.service.ts │ ├── shared │ │ └── index.ts │ ├── vadacl │ │ ├── interfaces.ts │ │ ├── messages │ │ │ └── messages-en.ts │ │ ├── patterns │ │ │ └── patterns-en.ts │ │ ├── vadacl.ts │ │ └── validation-methods.ts │ └── version │ │ ├── index.ts │ │ ├── version.component.html │ │ ├── version.component.spec.ts │ │ ├── version.component.ts │ │ ├── version.service.spec.ts │ │ └── version.service.ts ├── favicon.ico ├── index.html ├── main.ts ├── system-config.ts ├── tsconfig.json └── typings.d.ts ├── tslint.json └── typings.json /.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | end_of_line = lf 9 | insert_final_newline = true 10 | trim_trailing_whitespace = true 11 | 12 | [*.md] 13 | max_line_length = 0 14 | trim_trailing_whitespace = false 15 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /dist 5 | /tmp 6 | 7 | # dependencies 8 | /node_modules 9 | /bower_components 10 | 11 | # IDEs and editors 12 | /.idea 13 | .project 14 | .classpath 15 | *.launch 16 | .settings/ 17 | 18 | # misc 19 | /.sass-cache 20 | /connect.lock 21 | /coverage/* 22 | /libpeerconnection.log 23 | npm-debug.log 24 | testem.log 25 | /typings 26 | 27 | # e2e 28 | /e2e/*.js 29 | /e2e/*.map 30 | 31 | #System Files 32 | .DS_Store 33 | Thumbs.db 34 | 35 | #Scratch 36 | /scratch 37 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # angular2-sandbox-guildrunner 2 | The GuildRunner web application is a sandbox project for learning how to build Angular 2 web applications through 3 | research and experimentation. Blog posts concerning the evolution of the project can be found at 4 | [http://www.thoughtdelimited.org/thoughts](http://www.thoughtdelimited.org/thoughts/) 5 | 6 | ## Angular / Angular CLI Version Notes 7 | 8 | As of release 0.0.3, this application is built around Angular 2 release candidate 5 (RC5) and Angular CLI version beta.10. So it does not 9 | utilize Webpack as its module loader (it uses SystemJS), but it does use the ngModule feature introduced in Angular 2 RC5. 10 | 11 | ## Installation Instructions 12 | 13 | To download and execute this web application on your own system, perform the following steps: 14 | 15 | 1. Install [node.js](https://nodejs.org/en/) on your system if you don't already have it. 16 | 17 | 2. Perform a global install the latest version of [Angular CLI](https://cli.angular.io/) that uses SystemJS as its module loader. 18 | 1. The current version of Angular CLI still uses SystemJS, so you can perform the install with the following 19 | command: **npm install -g angular-cli**. 20 | 2. In the near future, Angular CLI will use Webpack as its module loader, at which point you would need to 21 | install the last SystemJS version rather than the current CLI version. 22 | 23 | 3. Download the repo to a project folder on your system. 24 | 25 | 4. Open a terminal/command prompt in the project folder and execute the following commands: 26 | 1. **npm install** to download and install the necessary node modules (this will take at least a few minutes) 27 | 2. **ng serve**, which will create a "dist" folder in the project and will serve the application 28 | 29 | 30 | ## Release Highlights 31 | 32 | ### 0.0.7 33 | 34 | * Revised the sandbox Chapter edit form to use the [vadacl](https://github.com/bcswartz/vadacl) validation library, 35 | which allows developers to define validation rules at both the data object and component level. 36 | 37 | ### 0.0.6 38 | 39 | * Created a sandbox version of a Chapter edit form using reactive form classes (FormGroup, FormArray, and FormControl) 40 | and Validators. 41 | 42 | ### 0.0.5 43 | 44 | * Removed Address and Member domain classes; added Person, Location, Chapter, ChapterLocation, and ChapterMember classes; refactored Guild class 45 | * Created new approach to setting domain class property defaults and setting property values in the constructor 46 | * Created sandbox views and master list views for Chapters and ChapterMembers 47 | * Utilized Promise.all() to resolve multiple promises in component methods that need data from multiple service methods 48 | 49 | ### 0.0.4 50 | 51 | * Added "incorporationYear" and "email" properties to the Guild data and domain class 52 | * Refactored the Guild domain class to allow it to be instantiated without data 53 | * Created basic add/edit form for guild objects 54 | * Created first draft of proof-of-concept for validating a pre-RC6 template-driven form 55 | * Created HttpResponse object for transporting HTTP response data from the service to the component 56 | 57 | ### 0.0.3 58 | 59 | * Upgraded Angular modules to release candidate 5 (RC5) 60 | * Refactored routing code to use latest routing setup and syntax 61 | * Refactored multiple files to utilize ngModule introduced in RC5 62 | * Moved sandbox feature files into separate module and routing file 63 | 64 | ### 0.0.2 65 | 66 | * Added Bootstrap navigation bar 67 | * Added routing 68 | * Created guild, address, and member data and domain classes 69 | * Created "sandbox" area of application to hold experimental/diagnostic features 70 | * Created guild master list component to display data from instances of the Guild domain class 71 | 72 | ### 0.0.1 73 | 74 | * Basic application foundation established 75 | * Added [in-memory web API](https://angular.io/docs/ts/latest/guide/server-communication.html#!#in-mem-web-api) to application to make use of mock data 76 | * Created "db" folder to hold mock data exports 77 | 78 | 79 | -------------------------------------------------------------------------------- /angular-cli-build.js: -------------------------------------------------------------------------------- 1 | // Angular-CLI build configuration 2 | // This file lists all the node_modules files that will be used in a build 3 | // Also see https://github.com/angular/angular-cli/wiki/3rd-party-libs 4 | 5 | /* global require, module */ 6 | 7 | var Angular2App = require('angular-cli/lib/broccoli/angular2-app'); 8 | 9 | module.exports = function(defaults) { 10 | return new Angular2App(defaults, { 11 | vendorNpmFiles: [ 12 | 'systemjs/dist/system-polyfills.js', 13 | 'systemjs/dist/system.src.js', 14 | 'zone.js/dist/**/*.+(js|js.map)', 15 | 'es6-shim/es6-shim.js', 16 | 'reflect-metadata/**/*.+(ts|js|js.map)', 17 | 'rxjs/**/*.+(js|js.map)', 18 | '@angular/**/*.+(js|js.map)', 19 | 'angular2-in-memory-web-api/*.+(js)' 20 | ] 21 | }); 22 | }; 23 | -------------------------------------------------------------------------------- /angular-cli.json: -------------------------------------------------------------------------------- 1 | { 2 | "project": { 3 | "version": "1.0.0-beta.10", 4 | "name": "guildrunner" 5 | }, 6 | "apps": [ 7 | { 8 | "main": "src/main.ts", 9 | "tsconfig": "src/tsconfig.json", 10 | "mobile": false 11 | } 12 | ], 13 | "addons": [], 14 | "packages": [], 15 | "e2e": { 16 | "protractor": { 17 | "config": "config/protractor.conf.js" 18 | } 19 | }, 20 | "test": { 21 | "karma": { 22 | "config": "config/karma.conf.js" 23 | } 24 | }, 25 | "defaults": { 26 | "prefix": "app", 27 | "sourceDir": "src", 28 | "styleExt": "css", 29 | "prefixInterfaces": false, 30 | "lazyRoutePrefix": "+" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /config/environment.dev.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: false 3 | }; 4 | -------------------------------------------------------------------------------- /config/environment.js: -------------------------------------------------------------------------------- 1 | // Angular-CLI server configuration 2 | // Unrelated to environment.dev|prod.ts 3 | 4 | /* jshint node: true */ 5 | 6 | module.exports = function(environment) { 7 | return { 8 | environment: environment, 9 | baseURL: '/', 10 | locationType: 'auto' 11 | }; 12 | }; 13 | -------------------------------------------------------------------------------- /config/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true 3 | }; 4 | -------------------------------------------------------------------------------- /config/karma-test-shim.js: -------------------------------------------------------------------------------- 1 | // Test shim for Karma, needed to load files via SystemJS 2 | 3 | /*global jasmine, __karma__, window*/ 4 | Error.stackTraceLimit = Infinity; 5 | jasmine.DEFAULT_TIMEOUT_INTERVAL = 1000; 6 | 7 | __karma__.loaded = function () { 8 | }; 9 | 10 | var distPath = '/base/dist/'; 11 | var appPaths = ['app']; //Add all valid source code folders here 12 | 13 | function isJsFile(path) { 14 | return path.slice(-3) == '.js'; 15 | } 16 | 17 | function isSpecFile(path) { 18 | return path.slice(-8) == '.spec.js'; 19 | } 20 | 21 | function isAppFile(path) { 22 | return isJsFile(path) && appPaths.some(function(appPath) { 23 | var fullAppPath = distPath + appPath + '/'; 24 | return path.substr(0, fullAppPath.length) == fullAppPath; 25 | }); 26 | } 27 | 28 | var allSpecFiles = Object.keys(window.__karma__.files) 29 | .filter(isSpecFile) 30 | .filter(isAppFile); 31 | 32 | // Load our SystemJS configuration. 33 | System.config({ 34 | baseURL: distPath 35 | }); 36 | 37 | System.import('system-config.js').then(function() { 38 | // Load and configure the TestComponentBuilder. 39 | return Promise.all([ 40 | System.import('@angular/core/testing'), 41 | System.import('@angular/platform-browser-dynamic/testing') 42 | ]).then(function (providers) { 43 | var testing = providers[0]; 44 | var testingBrowser = providers[1]; 45 | 46 | testing.setBaseTestProviders(testingBrowser.TEST_BROWSER_DYNAMIC_PLATFORM_PROVIDERS, 47 | testingBrowser.TEST_BROWSER_DYNAMIC_APPLICATION_PROVIDERS); 48 | }); 49 | }).then(function() { 50 | // Finally, load all spec files. 51 | // This will run the tests directly. 52 | return Promise.all( 53 | allSpecFiles.map(function (moduleName) { 54 | return System.import(moduleName); 55 | })); 56 | }).then(__karma__.start, __karma__.error); 57 | -------------------------------------------------------------------------------- /config/karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration file, see link for more information 2 | // https://karma-runner.github.io/0.13/config/configuration-file.html 3 | 4 | module.exports = function (config) { 5 | config.set({ 6 | basePath: '..', 7 | frameworks: ['jasmine'], 8 | plugins: [ 9 | require('karma-jasmine'), 10 | require('karma-chrome-launcher') 11 | ], 12 | customLaunchers: { 13 | // chrome setup for travis CI using chromium 14 | Chrome_travis_ci: { 15 | base: 'Chrome', 16 | flags: ['--no-sandbox'] 17 | } 18 | }, 19 | files: [ 20 | { pattern: 'dist/vendor/es6-shim/es6-shim.js', included: true, watched: false }, 21 | { pattern: 'dist/vendor/zone.js/dist/zone.js', included: true, watched: false }, 22 | { pattern: 'dist/vendor/reflect-metadata/Reflect.js', included: true, watched: false }, 23 | { pattern: 'dist/vendor/systemjs/dist/system-polyfills.js', included: true, watched: false }, 24 | { pattern: 'dist/vendor/systemjs/dist/system.src.js', included: true, watched: false }, 25 | { pattern: 'dist/vendor/zone.js/dist/async-test.js', included: true, watched: false }, 26 | { pattern: 'dist/vendor/zone.js/dist/fake-async-test.js', included: true, watched: false }, 27 | 28 | { pattern: 'config/karma-test-shim.js', included: true, watched: true }, 29 | 30 | // Distribution folder. 31 | { pattern: 'dist/**/*', included: false, watched: true } 32 | ], 33 | exclude: [ 34 | // Vendor packages might include spec files. We don't want to use those. 35 | 'dist/vendor/**/*.spec.js' 36 | ], 37 | preprocessors: {}, 38 | reporters: ['progress'], 39 | port: 9876, 40 | colors: true, 41 | logLevel: config.LOG_INFO, 42 | autoWatch: true, 43 | browsers: ['Chrome'], 44 | singleRun: false 45 | }); 46 | }; 47 | -------------------------------------------------------------------------------- /config/protractor.conf.js: -------------------------------------------------------------------------------- 1 | // Protractor configuration file, see link for more information 2 | // https://github.com/angular/protractor/blob/master/docs/referenceConf.js 3 | 4 | /*global jasmine */ 5 | var SpecReporter = require('jasmine-spec-reporter'); 6 | 7 | exports.config = { 8 | allScriptsTimeout: 11000, 9 | specs: [ 10 | '../e2e/**/*.e2e-spec.ts' 11 | ], 12 | capabilities: { 13 | 'browserName': 'chrome' 14 | }, 15 | directConnect: true, 16 | baseUrl: 'http://localhost:4200/', 17 | framework: 'jasmine', 18 | jasmineNodeOpts: { 19 | showColors: true, 20 | defaultTimeoutInterval: 30000, 21 | print: function() {} 22 | }, 23 | useAllAngular2AppRoots: true, 24 | beforeLaunch: function() { 25 | require('ts-node').register({ 26 | project: 'e2e' 27 | }); 28 | }, 29 | onPrepare: function() { 30 | jasmine.getEnv().addReporter(new SpecReporter()); 31 | } 32 | }; 33 | -------------------------------------------------------------------------------- /e2e/app.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import { GuildrunnerPage } from './app.po'; 2 | 3 | describe('guildrunner App', function() { 4 | let page: GuildrunnerPage; 5 | 6 | beforeEach(() => { 7 | page = new GuildrunnerPage(); 8 | }); 9 | 10 | it('should display main header text', () => { 11 | page.navigateTo(); 12 | expect(page.getMainHeaderText()).toEqual('GuildRunner'); 13 | }); 14 | 15 | it('should display the version number preceded by a label', () => { 16 | page.navigateTo(); 17 | expect(page.getVersionText()).toEqual('Version: 0.0.7'); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /e2e/app.po.ts: -------------------------------------------------------------------------------- 1 | export class GuildrunnerPage { 2 | navigateTo() { 3 | return browser.get('/'); 4 | } 5 | 6 | getMainHeaderText() { 7 | return element(by.css('app-root h1')).getText(); 8 | } 9 | 10 | getVersionText() { 11 | return element(by.css('app-root app-version p')).getText(); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /e2e/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "declaration": false, 5 | "emitDecoratorMetadata": true, 6 | "experimentalDecorators": true, 7 | "mapRoot": "", 8 | "module": "commonjs", 9 | "moduleResolution": "node", 10 | "noEmitOnError": true, 11 | "noImplicitAny": false, 12 | "rootDir": ".", 13 | "sourceMap": true, 14 | "sourceRoot": "/", 15 | "target": "es5" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /e2e/typings.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "guildrunner", 3 | "version": "0.0.0", 4 | "license": "MIT", 5 | "angular-cli": {}, 6 | "scripts": { 7 | "start": "ng serve", 8 | "postinstall": "typings install", 9 | "lint": "tslint \"src/**/*.ts\"", 10 | "test": "ng test", 11 | "pree2e": "webdriver-manager update", 12 | "e2e": "protractor" 13 | }, 14 | "private": true, 15 | "dependencies": { 16 | "@angular/common": "2.0.0-rc.5", 17 | "@angular/compiler": "2.0.0-rc.5", 18 | "@angular/core": "2.0.0-rc.5", 19 | "@angular/forms": "0.3.0", 20 | "@angular/http": "2.0.0-rc.5", 21 | "@angular/platform-browser": "2.0.0-rc.5", 22 | "@angular/platform-browser-dynamic": "2.0.0-rc.5", 23 | "@angular/router": "3.0.0-rc.1", 24 | "angular2-in-memory-web-api": "0.0.15", 25 | "es6-shim": "0.35.1", 26 | "reflect-metadata": "0.1.3", 27 | "rxjs": "5.0.0-beta.6", 28 | "systemjs": "0.19.27", 29 | "zone.js": "0.6.12" 30 | }, 31 | "devDependencies": { 32 | "angular-cli": "1.0.0-beta.10", 33 | "codelyzer": "0.0.20", 34 | "ember-cli-inject-live-reload": "1.4.0", 35 | "jasmine-core": "2.4.1", 36 | "jasmine-spec-reporter": "2.5.0", 37 | "karma": "0.13.22", 38 | "karma-chrome-launcher": "0.2.3", 39 | "karma-jasmine": "0.3.8", 40 | "protractor": "3.3.0", 41 | "ts-node": "0.5.5", 42 | "tslint": "3.11.0", 43 | "typescript": "1.8.10", 44 | "typings": "1.3.1" 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /public/.npmignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcswartz/angular2-sandbox-guildrunner/c57c5ff1083b1b6ae5a1b6d5ae93adc9e547efa8/public/.npmignore -------------------------------------------------------------------------------- /src/app/app.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcswartz/angular2-sandbox-guildrunner/c57c5ff1083b1b6ae5a1b6d5ae93adc9e547efa8/src/app/app.component.css -------------------------------------------------------------------------------- /src/app/app.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |

{{title}}

5 |
6 |
7 | 8 |
9 |
10 | 11 |
12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/app/app.component.spec.ts: -------------------------------------------------------------------------------- 1 | /* tslint:disable:no-unused-variable */ 2 | 3 | import { addProviders, async, inject } from '@angular/core/testing'; 4 | import { AppComponent } from './app.component'; 5 | 6 | describe('App: Guildrunner', () => { 7 | beforeEach(() => { 8 | addProviders([AppComponent]); 9 | }); 10 | 11 | it('should create the app', 12 | inject([AppComponent], (app: AppComponent) => { 13 | expect(app).toBeTruthy(); 14 | })); 15 | 16 | it('should have as title \'app works!\'', 17 | inject([AppComponent], (app: AppComponent) => { 18 | expect(app.title).toEqual('GuildRunner'); 19 | })); 20 | }); 21 | -------------------------------------------------------------------------------- /src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | moduleId: module.id, 5 | selector: 'app-root', 6 | templateUrl: 'app.component.html', 7 | styleUrls: ['app.component.css'] 8 | }) 9 | 10 | export class AppComponent { 11 | title = 'GuildRunner'; 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/app/app.module.ts: -------------------------------------------------------------------------------- 1 | //Modules and routing imports 2 | import { NgModule } from '@angular/core'; 3 | import { BrowserModule } from '@angular/platform-browser'; 4 | import { HttpModule } from '@angular/http'; 5 | import { FormsModule, ReactiveFormsModule } from '@angular/forms'; 6 | import { SandboxModule } from './sandbox/sandbox.module'; 7 | import { routing } from './app.routing'; 8 | 9 | //Declarations (components, directives, and pipes) 10 | import { AppComponent } from './app.component'; 11 | import { VersionComponent } from './version/version.component'; 12 | import { MainNavigationComponent } from './main-navigation/main-navigation.component'; 13 | import { HomeComponent } from "./home/home.component"; 14 | import { GuildsMasterComponent } from "./guilds-master/guilds-master.component"; 15 | import { GuildsDetailComponent } from "./guilds-detail/guilds-detail.component"; 16 | import { ChaptersMasterComponent } from "./chapters-master/chapters-master.component"; 17 | import { MembersMasterComponent } from "./members-master/members-master.component"; 18 | 19 | //Providers (services) 20 | import { VersionService } from './version/version.service'; 21 | import { GuildService } from './guild.service'; 22 | import { ChapterService } from "./chapter.service"; 23 | import { MemberService } from "./member.service"; 24 | 25 | // Imports for loading & configuring the in-memory web api 26 | import { XHRBackend } from '@angular/http'; 27 | import { InMemoryBackendService, SEED_DATA } from 'angular2-in-memory-web-api'; 28 | import { InMemoryDataService } from './in-memory-data.service'; 29 | 30 | 31 | @NgModule({ 32 | imports: [ 33 | BrowserModule, 34 | HttpModule, 35 | FormsModule, 36 | ReactiveFormsModule, 37 | routing, 38 | SandboxModule 39 | ], 40 | 41 | declarations: [ 42 | AppComponent, 43 | VersionComponent, 44 | MainNavigationComponent, 45 | HomeComponent, 46 | GuildsMasterComponent, 47 | GuildsDetailComponent, 48 | ChaptersMasterComponent, 49 | MembersMasterComponent 50 | ], 51 | 52 | providers: [ 53 | { provide: XHRBackend, useClass: InMemoryBackendService }, // in-mem server 54 | { provide: SEED_DATA, useClass: InMemoryDataService }, // in-mem server data 55 | VersionService, 56 | GuildService, 57 | ChapterService, 58 | MemberService 59 | ], 60 | 61 | bootstrap: [ 62 | AppComponent 63 | ], 64 | }) 65 | 66 | export class AppModule {} 67 | 68 | -------------------------------------------------------------------------------- /src/app/app.routing.ts: -------------------------------------------------------------------------------- 1 | import { Routes, RouterModule } from '@angular/router'; 2 | 3 | import { GuildsMasterComponent } from "./guilds-master/guilds-master.component"; 4 | import { HomeComponent } from "./home/home.component"; 5 | import { GuildsDetailComponent } from "./guilds-detail/guilds-detail.component"; 6 | import { ChaptersMasterComponent } from "./chapters-master/chapters-master.component"; 7 | import { MembersMasterComponent } from "./members-master/members-master.component"; 8 | 9 | const appRoutes: Routes = [ 10 | { path: 'home', component: HomeComponent }, 11 | { path: 'guilds', component: GuildsMasterComponent }, 12 | { path: 'guilds/:id', component: GuildsDetailComponent}, //Edit route 13 | { path: 'guild', component: GuildsDetailComponent }, //Add route 14 | { path: 'chapters', component: ChaptersMasterComponent}, 15 | { path: 'members', component: MembersMasterComponent }, 16 | { path: '', redirectTo: '/home', pathMatch: 'full' } 17 | ]; 18 | 19 | export const routing = RouterModule.forRoot( appRoutes ); 20 | -------------------------------------------------------------------------------- /src/app/chapter.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { Http, Headers } from '@angular/http'; 3 | 4 | import { HttpResponse } from './domain/http-response'; 5 | import { Chapter } from './domain/chapter'; 6 | 7 | import 'rxjs/add/operator/toPromise'; 8 | 9 | @Injectable() 10 | export class ChapterService { 11 | 12 | private chapterUrl = 'app/chapters'; 13 | 14 | constructor( private http: Http ) { } 15 | 16 | getChapters() { 17 | return this.http.get( this.chapterUrl ) 18 | .toPromise() 19 | .then( response => { 20 | let serviceResponse = new HttpResponse( response ); 21 | serviceResponse.data = response.json().data; 22 | return serviceResponse; 23 | }) 24 | .catch( error => { 25 | let serviceResponse = new HttpResponse( error ); 26 | return serviceResponse; 27 | }); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/app/chapters-master/chapters-master.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcswartz/angular2-sandbox-guildrunner/c57c5ff1083b1b6ae5a1b6d5ae93adc9e547efa8/src/app/chapters-master/chapters-master.component.css -------------------------------------------------------------------------------- /src/app/chapters-master/chapters-master.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |

Chapters

4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 |
IDNameHead Chapter?GuildFounded
{{chapter.id}}{{chapter.name}}{{chapter.headChapter ? 'Yes' : 'No'}}{{guilds[ chapter.guildId ].name}}{{chapter.founded}}
24 |
25 |
26 | -------------------------------------------------------------------------------- /src/app/chapters-master/chapters-master.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { ChapterService } from '../chapter.service'; 3 | import { GuildService } from '../guild.service'; 4 | import { Chapter } from '../domain/chapter'; 5 | import { HttpResponse } from '../domain/http-response'; 6 | 7 | @Component({ 8 | moduleId: module.id, 9 | selector: 'app-chapters-master', 10 | templateUrl: 'chapters-master.component.html', 11 | styleUrls: ['chapters-master.component.css'] 12 | }) 13 | export class ChaptersMasterComponent implements OnInit { 14 | 15 | chapters: Chapter[] = []; 16 | guilds: any = {}; 17 | 18 | constructor( 19 | private chapterService: ChapterService, 20 | private guildService: GuildService 21 | ) { } 22 | 23 | ngOnInit() { 24 | 25 | Promise.all( [ 26 | this.chapterService.getChapters(), 27 | this.guildService.getGuilds() 28 | ] 29 | ).then( (results:Promise[]) => { 30 | results[0]['data'].forEach(chapterData => { 31 | this.chapters.push(new Chapter(chapterData)) 32 | }); 33 | results[1]['data'].forEach(guildData => { 34 | this.guilds[guildData.id] = guildData; 35 | }); 36 | }); 37 | 38 | } 39 | 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/app/chapters-master/index.ts: -------------------------------------------------------------------------------- 1 | export * from './chapters-master.component'; 2 | -------------------------------------------------------------------------------- /src/app/db/chapter-members.ts: -------------------------------------------------------------------------------- 1 | import { people } from './people'; 2 | 3 | function createChapterMember( id, chapterId, startDate, endDate, isActive ) { 4 | return { 5 | firstName: people[id].firstName, 6 | middleName: people[id].middleName, 7 | lastName: people[id].lastName, 8 | phone: people[id].phone, 9 | altPhone: people[id].altPhone, 10 | email: people[id].email, 11 | isUndead: people[id].isUndead, 12 | location: { 13 | address: people[id].location.address, 14 | address2: people[id].location.address2, 15 | city: people[id].location.city, 16 | stateProvince: people[id].location.stateProvince, 17 | postalCode: people[id].location.postalCode 18 | }, 19 | id: id, 20 | chapterId: chapterId, 21 | startDate: startDate, 22 | endDate: endDate, 23 | isActive: isActive 24 | } 25 | } 26 | 27 | let chapterMembers = [ 28 | createChapterMember( 1, 1, '2/3/1987', null, true ), 29 | createChapterMember( 2, 1, '7/8/1991', '11/15/15', false ), 30 | createChapterMember( 3, 1, '11/4/1993', null, true ), 31 | createChapterMember( 4, 1, '9/14/2002', null, true ), 32 | createChapterMember( 5, 2, '3/17/2001', null, true ), 33 | createChapterMember( 6, 2, '2/4/1997', null, true ), 34 | createChapterMember( 7, 2, '8/1/1988', null, true ), 35 | createChapterMember( 8, 3, '5/24/2003', null, true ), 36 | createChapterMember( 9, 3, '10/14/1991', '10/5/14', false ), 37 | createChapterMember( 10, 3, '2/11/1990', null, true ), 38 | createChapterMember( 11, 4, '3/4/1991', null, true ), 39 | createChapterMember( 12, 4, '8/14/1998', null, true ), 40 | createChapterMember( 13, 4, '9/3/1997', null, true ), 41 | createChapterMember( 14, 4, '4/27/2005', null, true ), 42 | createChapterMember( 15, 5, '10/23/1992', null, true ), 43 | createChapterMember( 16, 5, '12/4/1984', null, true ), 44 | createChapterMember( 17, 6, '10/13/1998', null, true ), 45 | createChapterMember( 18, 6, '3/19/2008', null, true ), 46 | createChapterMember( 19, 6, '9/13/2003', '12/1/15', false ), 47 | createChapterMember( 20, 7, '11/11/2009', null, true ), 48 | createChapterMember( 21, 7, '6/9/2000', null, true ), 49 | createChapterMember( 22, 7, '3/2/1998', null, true ), 50 | createChapterMember( 23, 8, '7/15/2011', null, true ), 51 | createChapterMember( 24, 8, '6/1/1994', null, true ), 52 | createChapterMember( 25, 8, '7/1/1991', null, true ), 53 | createChapterMember( 26, 9, '1/13/2003', null, true ), 54 | createChapterMember( 27, 9, '4/26/2004', '3/3/2016', false ), 55 | createChapterMember( 28, 9, '12/13/2012', null, true ), 56 | createChapterMember( 29, 9, '4/6/2008', null, true ), 57 | createChapterMember( 30, 9, '2/22/1999', null, true ), 58 | createChapterMember( 31, 10, '3/23/2010', null, true ), 59 | createChapterMember( 32, 10, '2/17/2001', null, true ), 60 | createChapterMember( 33, 10, '7/23/2002', null, true ), 61 | createChapterMember( 34, 10, '2/7/1997', null, true ), 62 | createChapterMember( 35, 10, '7/8/1995', '8/9/1999', false ), 63 | createChapterMember( 36, 10, '4/4/2001', null, true ), 64 | createChapterMember( 37, 10, '9/21/2004', null, true ), 65 | createChapterMember( 38, 1, '8/2/1996', null, true ), 66 | createChapterMember( 39, 1, '11/2/1988', null, true ), 67 | createChapterMember( 40, 2, '5/5/1993', null, true ), 68 | ]; 69 | 70 | export { chapterMembers } 71 | -------------------------------------------------------------------------------- /src/app/db/chapters.ts: -------------------------------------------------------------------------------- 1 | let chapters = [ 2 | { 3 | id: 1, 4 | guildId: 1, 5 | name: 'West Central', 6 | headChapter: true, 7 | founded: '4/5/1878', 8 | email: 'bsmiths_wc@citywire.com', 9 | location: { 10 | address: '136 Chanter Circle', 11 | address2: null, 12 | city: 'New London', 13 | stateProvince: 'Melon', 14 | postalCode: '02001-0053', 15 | entryPoints: 2, 16 | floors: 2, 17 | hasBasement: true, 18 | rooftopAccess: false 19 | }, 20 | defenses: [ 1, 2, 5, 6 ] 21 | }, 22 | { 23 | id: 2, 24 | guildId: 1, 25 | name: 'Royal District', 26 | headChapter: false, 27 | founded: '11/21/1931', 28 | email: 'bsmiths_rd@citywire.com', 29 | location: { 30 | address: '2379 Kings Way', 31 | address2: null, 32 | city: 'New London', 33 | stateProvince: 'Aristo', 34 | postalCode: '05001-1100', 35 | entryPoints: 1, 36 | floors: 3, 37 | hasBasement: true, 38 | rooftopAccess: true 39 | }, 40 | defenses: [ 3, 7, 8 ] 41 | }, 42 | { 43 | id: 3, 44 | guildId: 1, 45 | name: 'Fountain District', 46 | headChapter: false, 47 | founded: '10/13/1899', 48 | email: 'bsmiths_fd@citywire.com', 49 | location: { 50 | address: '34 Stellar Blvd', 51 | address2: null, 52 | city: 'New London', 53 | stateProvince: 'Alcott', 54 | postalCode: '01001-1100', 55 | entryPoints: 3, 56 | floors: 1, 57 | hasBasement: false, 58 | rooftopAccess: false 59 | }, 60 | defenses: [ 1, 2, 4 ] 61 | }, 62 | { 63 | id: 4, 64 | guildId: 2, 65 | name: 'Eastern Market', 66 | headChapter: true, 67 | founded: '6/16/1934', 68 | email: 'eastercontractkill@citywire.com', 69 | location: { 70 | address: '6870 Halfwit Ave.', 71 | address2: null, 72 | city: 'New London', 73 | stateProvince: 'Melon', 74 | postalCode: '02001-0000', 75 | entryPoints: 2, 76 | floors: 2, 77 | hasBasement: false, 78 | rooftopAccess: true 79 | }, 80 | defenses: [ 1, 2, 3, 5, 8 ] 81 | }, 82 | { 83 | id: 5, 84 | guildId: 2, 85 | name: 'Government Center', 86 | headChapter: false, 87 | founded: '4/7/1955', 88 | email: 'politikill@citywire.com', 89 | location: { 90 | address: '28810 North Alley', 91 | address2: '2nd Floor', 92 | city: 'New London', 93 | stateProvince: 'Alcott', 94 | postalCode: '01001-0450', 95 | entryPoints: 1, 96 | floors: 1, 97 | hasBasement: false, 98 | rooftopAccess: false 99 | }, 100 | defenses: [ 3, 4, 8 ] 101 | }, 102 | { 103 | id: 6, 104 | guildId: 2, 105 | name: 'South End', 106 | headChapter: false, 107 | founded: '4/17/1975', 108 | email: 'takemout@citywire.com', 109 | location: { 110 | address: '24 North Cyon Str', 111 | address2: null, 112 | city: 'Kent', 113 | stateProvince: 'Dover', 114 | postalCode: '02001-0000', 115 | entryPoints: 1, 116 | floors: 3, 117 | hasBasement: false, 118 | rooftopAccess: true 119 | }, 120 | defenses: [ 2, 3, 5 ] 121 | }, 122 | { 123 | id: 7, 124 | guildId: 2, 125 | name: 'Underworld', 126 | headChapter: false, 127 | founded: '3/21/1989', 128 | email: 'deathtodeath@citywire.com', 129 | location: { 130 | address: '100 Brimstone Court', 131 | address2: null, 132 | city: 'Lower London', 133 | stateProvince: 'Sulfur', 134 | postalCode: '66602-9000', 135 | entryPoints: 4, 136 | floors: 1, 137 | hasBasement: true, 138 | rooftopAccess: false 139 | }, 140 | defenses: [ 1, 5, 8 ] 141 | }, 142 | { 143 | id: 8, 144 | guildId: 3, 145 | name: 'Financial District', 146 | headChapter: true, 147 | founded: '12/12/2001', 148 | email: 'robinhoods@citywire.com', 149 | location: { 150 | address: '101 Banker Lane', 151 | address2: null, 152 | city: 'New London', 153 | stateProvince: 'Alcott', 154 | postalCode: '01001-0040', 155 | entryPoints: 2, 156 | floors: 4, 157 | hasBasement: true, 158 | rooftopAccess: true 159 | }, 160 | defenses: [ 1, 6 ] 161 | }, 162 | { 163 | id: 9, 164 | guildId: 3, 165 | name: 'West Kent', 166 | headChapter: false, 167 | founded: '1/3/1965', 168 | email: 'kentcleptos@citywire.com', 169 | location: { 170 | address: '5466 Closing Court', 171 | address2: null, 172 | city: 'Kent', 173 | stateProvince: 'Dover', 174 | postalCode: '03001-3330', 175 | entryPoints: 3, 176 | floors: 2, 177 | hasBasement: false, 178 | rooftopAccess: true 179 | }, 180 | defenses: [ 7, 8 ] 181 | }, 182 | { 183 | id: 10, 184 | guildId: 3, 185 | name: 'North District', 186 | headChapter: false, 187 | founded: '8/25/2003', 188 | email: 'northerncrooks@citywire.com', 189 | location: { 190 | address: '234 Spruce Street', 191 | address2: null, 192 | city: 'New London', 193 | stateProvince: 'Melon', 194 | postalCode: '02001-4401', 195 | entryPoints: 2, 196 | floors: 2, 197 | hasBasement: false, 198 | rooftopAccess: true 199 | }, 200 | defenses: [ 1, 2, 3, 4 ] 201 | }, 202 | ]; 203 | 204 | export { chapters } 205 | 206 | -------------------------------------------------------------------------------- /src/app/db/defense-measures.ts: -------------------------------------------------------------------------------- 1 | let defenseMeasures = [ 2 | { id: 1, label: 'Security cameras' }, 3 | { id: 2, label: 'Window alarms' }, 4 | { id: 3, label: 'Guard wolves' }, 5 | { id: 4, label: 'Booby traps' }, 6 | { id: 5, label: 'Safe room' }, 7 | { id: 6, label: 'Professional guards' }, 8 | { id: 7, label: 'Volunteer guards' }, 9 | { id: 8, label: 'Sprinkler system' } 10 | ] 11 | 12 | export { defenseMeasures } 13 | -------------------------------------------------------------------------------- /src/app/db/guilds.ts: -------------------------------------------------------------------------------- 1 | let guilds = [ 2 | { 3 | id: 1, 4 | name: "Blacksmiths", 5 | incorporationYear: 1878, 6 | email: 'bsmithsinc@citywire.com', 7 | expenses: 10000, 8 | revenue: 15000, 9 | }, 10 | { 11 | id: 2, 12 | name: "Assassins", 13 | incorporationYear: 1713, 14 | email: 'killercorp@gcitywire.com', 15 | expenses: 22000, 16 | revenue: 18500 17 | }, 18 | { 19 | id: 3, 20 | name: "Thieves", 21 | incorporationYear: 1931, 22 | email: 'moneyshift@citywire.com', 23 | expenses: 7000, 24 | revenue: 14750 25 | } 26 | ]; 27 | 28 | export { guilds } 29 | -------------------------------------------------------------------------------- /src/app/db/people.ts: -------------------------------------------------------------------------------- 1 | let people = [ 2 | { 3 | firstName: 'Fenrik', 4 | middleName: null, 5 | lastName: 'Thane', 6 | phone: '555-324-8987', 7 | altPhone: null, 8 | email: 'fthane@citywire.com', 9 | isUndead: false, 10 | location: { 11 | address: '101 Center Lane', 12 | address2: null, 13 | city: 'New London', 14 | stateProvince: 'Alcott', 15 | postalCode: '01001-0000' 16 | } 17 | }, 18 | { 19 | firstName: 'Jalak', 20 | middleName: 'R.', 21 | lastName: 'Crellen', 22 | phone: '555-676-5453', 23 | altPhone: null, 24 | email: 'jcrell@citywire.com', 25 | isUndead: false, 26 | location: { 27 | address: '798 Walker Lane', 28 | address2: null, 29 | city: 'New London', 30 | stateProvince: 'Melon', 31 | postalCode: '02001-0000' 32 | } 33 | }, 34 | { 35 | firstName: 'Raiken', 36 | middleName: 'Crushing', 37 | lastName: 'Bellanous', 38 | phone: '555-998-8971', 39 | altPhone: null, 40 | email: 'rbellanous@netforge.org', 41 | isUndead: false, 42 | location: { 43 | address: '13 Westerland Way', 44 | address2: null, 45 | city: 'New London', 46 | stateProvince: 'Alcott', 47 | postalCode: '01001-0400' 48 | } 49 | }, 50 | { 51 | firstName: 'Roland', 52 | middleName: null, 53 | lastName: 'Cagznice', 54 | phone: '554-766-0987', 55 | altPhone: null, 56 | email: 'rcog@netforge.org', 57 | isUndead: false, 58 | location: { 59 | address: '132 Belamy Court', 60 | address2: null, 61 | city: 'New London', 62 | stateProvince: 'Melon', 63 | postalCode: '02001-0050' 64 | } 65 | }, 66 | { 67 | firstName: 'Jerriack', 68 | middleName: 'Carlos', 69 | lastName: 'Selfane', 70 | phone: '555-087-1551', 71 | altPhone: null, 72 | email: 'jselfane@citywire.com', 73 | isUndead: false, 74 | location: { 75 | address: '89 Welling Gardens', 76 | address2: 'Apt. 10', 77 | city: 'New London', 78 | stateProvince: 'Alcott', 79 | postalCode: '01001-0006' 80 | } 81 | }, 82 | { 83 | firstName: 'Bablet', 84 | middleName: null, 85 | lastName: 'Crosswind', 86 | phone: '555-544-0312', 87 | altPhone: '666-111-0981', 88 | email: 'bcross@departed.com', 89 | isUndead: true, 90 | location: { 91 | address: '23 Hades Ave.', 92 | address2: null, 93 | city: 'Lower London', 94 | stateProvince: 'Underland', 95 | postalCode: '6661-2000' 96 | } 97 | }, 98 | { 99 | firstName: 'Lanfar', 100 | middleName: 'Cole', 101 | lastName: 'Terrios', 102 | phone: '555-112-8725', 103 | altPhone: null, 104 | email: 'lterrios@citywire.com', 105 | isUndead: false, 106 | location: { 107 | address: '120 Windfar Lane', 108 | address2: null, 109 | city: 'New London', 110 | stateProvince: 'Melon', 111 | postalCode: '02001-0000' 112 | } 113 | }, 114 | { 115 | firstName: 'Barker', 116 | middleName: null, 117 | lastName: 'Rafina', 118 | phone: '555-763-7972', 119 | altPhone: null, 120 | email: 'brafina@netforge.org', 121 | isUndead: false, 122 | location: { 123 | address: '125 Bastion Blvd.', 124 | address2: null, 125 | city: 'New London', 126 | stateProvince: 'Alcott', 127 | postalCode: '01001-0600' 128 | } 129 | }, 130 | { 131 | firstName: 'Kalassian', 132 | middleName: null, 133 | lastName: 'Tremane', 134 | phone: '555-144-7982', 135 | altPhone: null, 136 | email: 'ktremane@citywire.com', 137 | isUndead: false, 138 | location: { 139 | address: '898 North Ave', 140 | address2: null, 141 | city: 'New London', 142 | stateProvince: 'Melon', 143 | postalCode: '02001-1500' 144 | } 145 | }, 146 | { 147 | firstName: 'Rafel', 148 | middleName: 'Callas', 149 | lastName: 'Mellofon', 150 | phone: '666-876-8891', 151 | altPhone: null, 152 | email: 'rmello@departed.com', 153 | isUndead: true, 154 | location: { 155 | address: '12 Everlasting Lane', 156 | address2: null, 157 | city: 'Lower London', 158 | stateProvince: 'Underland', 159 | postalCode: '66601-0000' 160 | } 161 | }, 162 | { 163 | firstName: 'Gregor', 164 | middleName: null, 165 | lastName: 'Sandoval', 166 | phone: '555-897-0098', 167 | altPhone: null, 168 | email: 'gsando@citywire.com', 169 | isUndead: false, 170 | location: { 171 | address: '12 Southwest Lane', 172 | address2: null, 173 | city: 'New London', 174 | stateProvince: 'Alcott', 175 | postalCode: '01001-0050' 176 | } 177 | }, 178 | { 179 | firstName: 'Braile', 180 | middleName: null, 181 | lastName: 'Snowden', 182 | phone: '555-087-7787', 183 | altPhone: null, 184 | email: 'bsnowden@netforge.org', 185 | isUndead: false, 186 | location: { 187 | address: '22 Bombshell Street', 188 | address2: null, 189 | city: 'New London', 190 | stateProvince: 'Rising', 191 | postalCode: '03001-0400' 192 | } 193 | }, 194 | { 195 | firstName: 'Jello', 196 | middleName: 'Chunky', 197 | lastName: 'Wellspring', 198 | phone: '555-877-6677', 199 | altPhone: null, 200 | email: 'jelloc@netforge.org', 201 | isUndead: false, 202 | location: { 203 | address: '102 Wellstone Street', 204 | address2: null, 205 | city: 'New London', 206 | stateProvince: 'Alcott', 207 | postalCode: '01001-0500' 208 | } 209 | }, 210 | { 211 | firstName: 'Laster', 212 | middleName: null, 213 | lastName: 'Kenton', 214 | phone: '555-812-6521', 215 | altPhone: null, 216 | email: 'lkent@citywire.com', 217 | isUndead: false, 218 | location: { 219 | address: '74 Brighton Ave.', 220 | address2: null, 221 | city: 'Kent', 222 | stateProvince: 'Dover', 223 | postalCode: '22001-0000' 224 | } 225 | }, 226 | { 227 | firstName: 'Quell', 228 | middleName: 'Bastion', 229 | lastName: 'Pollak', 230 | phone: '555-343-1100', 231 | altPhone: null, 232 | email: 'quall@netforge.org', 233 | isUndead: false, 234 | location: { 235 | address: '11290 Central Ave', 236 | address2: null, 237 | city: 'New London', 238 | stateProvince: 'Rising', 239 | postalCode: '03001-0200' 240 | } 241 | }, 242 | { 243 | firstName: 'Aldus', 244 | middleName: null, 245 | lastName: 'Renegade', 246 | phone: '555-019-8165', 247 | altPhone: null, 248 | email: 'arenegate@citywire.com', 249 | isUndead: false, 250 | location: { 251 | address: '20 Clown Street', 252 | address2: null, 253 | city: 'Kent', 254 | stateProvince: 'Dover', 255 | postalCode: '22001-0300' 256 | } 257 | }, 258 | { 259 | firstName: 'Danton', 260 | middleName: null, 261 | lastName: 'Profane', 262 | phone: '555-655-8791', 263 | altPhone: null, 264 | email: 'dprofane@departed.com', 265 | isUndead: true, 266 | location: { 267 | address: '1200 Hellfire Way', 268 | address2: null, 269 | city: 'Lower London', 270 | stateProvince: 'Underland', 271 | postalCode: '66601-0400' 272 | } 273 | }, 274 | { 275 | firstName: 'Montage', 276 | middleName: 'Caron', 277 | lastName: 'Zaire', 278 | phone: '555-898-0032', 279 | altPhone: null, 280 | email: 'mzaire@citywire.com', 281 | isUndead: false, 282 | location: { 283 | address: '43 Frankton Ave.', 284 | address2: null, 285 | city: 'New London', 286 | stateProvince: 'Melon', 287 | postalCode: '02001-1300' 288 | } 289 | }, 290 | { 291 | firstName: 'Blaze', 292 | middleName: null, 293 | lastName: 'Canton', 294 | phone: '555-003-9901', 295 | altPhone: null, 296 | email: 'bcanton@citywire.com', 297 | isUndead: false, 298 | location: { 299 | address: '32 Eleventh Street', 300 | address2: null, 301 | city: 'New London', 302 | stateProvince: 'Alcott', 303 | postalCode: '01001-4400' 304 | } 305 | }, 306 | { 307 | firstName: 'Amherst', 308 | middleName: null, 309 | lastName: 'Worthington', 310 | phone: '666-901-9090', 311 | altPhone: null, 312 | email: 'aworth@departed.com', 313 | isUndead: true, 314 | location: { 315 | address: '1001 Brimstone Court', 316 | address2: null, 317 | city: 'Lower London', 318 | stateProvince: 'Sulfur', 319 | postalCode: '66602-9000' 320 | } 321 | }, 322 | { 323 | firstName: 'Pellas', 324 | middleName: null, 325 | lastName: 'Grimwoire', 326 | phone: '555-101-8801', 327 | altPhone: null, 328 | email: 'pgrim@netforge.org', 329 | isUndead: false, 330 | location: { 331 | address: '29910 North Alley', 332 | address2: null, 333 | city: 'New London', 334 | stateProvince: 'Alcott', 335 | postalCode: '01001-0450' 336 | } 337 | }, 338 | { 339 | firstName: 'Cooland', 340 | middleName: null, 341 | lastName: 'Cassan', 342 | phone: '555-897-6575', 343 | altPhone: null, 344 | email: 'ccass@netforge.com', 345 | isUndead: false, 346 | location: { 347 | address: '144 Western Sun Street', 348 | address2: null, 349 | city: 'New London', 350 | stateProvince: 'Melon', 351 | postalCode: '02001-0000' 352 | } 353 | }, 354 | { 355 | firstName: 'Davin', 356 | middleName: null, 357 | lastName: 'Lannis', 358 | phone: '554-897-7919', 359 | altPhone: null, 360 | email: 'dlannis@citywire.com', 361 | isUndead: false, 362 | location: { 363 | address: '112 Wonder Lane', 364 | address2: null, 365 | city: 'Kent', 366 | stateProvince: 'Dover', 367 | postalCode: '02001-0000' 368 | } 369 | }, 370 | { 371 | firstName: 'Egon', 372 | middleName: 'Fullbring', 373 | lastName: 'Spandex', 374 | phone: '555-665-8971', 375 | altPhone: null, 376 | email: 'egons@netforge.org', 377 | isUndead: false, 378 | location: { 379 | address: '9879 Halfwit Ave.', 380 | address2: null, 381 | city: 'New London', 382 | stateProvince: 'Melon', 383 | postalCode: '02001-0000' 384 | } 385 | }, 386 | { 387 | firstName: 'Gator', 388 | middleName: null, 389 | lastName: 'Opperand', 390 | phone: '555-323-7212', 391 | altPhone: null, 392 | email: 'goppe@netforge.org', 393 | isUndead: false, 394 | location: { 395 | address: '898 Eastern Circle', 396 | address2: null, 397 | city: 'Kent', 398 | stateProvince: 'Dover', 399 | postalCode: '02001-0000' 400 | } 401 | }, 402 | { 403 | firstName: 'Olso', 404 | middleName: null, 405 | lastName: 'Greymane', 406 | phone: '666-811-880', 407 | altPhone: '555-722-2211', 408 | email: 'gmane@departed.com', 409 | isUndead: true, 410 | location: { 411 | address: '977 Basement Blvd.', 412 | address2: null, 413 | city: 'Lower London', 414 | stateProvince: 'Underland', 415 | postalCode: '66601-3300' 416 | } 417 | }, 418 | { 419 | firstName: 'Ellis', 420 | middleName: null, 421 | lastName: 'Wonders', 422 | phone: '555-341-4345', 423 | altPhone: null, 424 | email: 'ewonders@citywire.com', 425 | isUndead: false, 426 | location: { 427 | address: '1889 Promise Lane', 428 | address2: null, 429 | city: 'New London', 430 | stateProvince: 'Melon', 431 | postalCode: '02001-0876' 432 | } 433 | }, 434 | { 435 | firstName: 'Yalla', 436 | middleName: 'Angel', 437 | lastName: 'Flowers', 438 | phone: '555-271-3151', 439 | altPhone: null, 440 | email: 'yangel@netforge.org', 441 | isUndead: false, 442 | location: { 443 | address: '8979 Plain Place', 444 | address2: null, 445 | city: 'New London', 446 | stateProvince: 'Alcott', 447 | postalCode: '01001-1100' 448 | } 449 | }, 450 | { 451 | firstName: 'Chrysal', 452 | middleName: null, 453 | lastName: 'Erras', 454 | phone: '555-251-8711', 455 | altPhone: null, 456 | email: 'cerras@citywire.com', 457 | isUndead: false, 458 | location: { 459 | address: '766 Chanter Circle', 460 | address2: null, 461 | city: 'New London', 462 | stateProvince: 'Melon', 463 | postalCode: '02001-0053' 464 | } 465 | }, 466 | { 467 | firstName: 'Ja', 468 | middleName: null, 469 | lastName: 'Xandos', 470 | phone: '666-322-8981', 471 | altPhone: null, 472 | email: 'jxan@departed.com', 473 | isUndead: true, 474 | location: { 475 | address: '8981 Wandering Way', 476 | address2: null, 477 | city: 'Lower London', 478 | stateProvince: 'Underland', 479 | postalCode: '66601-3200' 480 | } 481 | }, 482 | { 483 | firstName: 'Wanda', 484 | middleName: null, 485 | lastName: 'Kessler', 486 | phone: '555-342-8913', 487 | altPhone: null, 488 | email: 'wk@netforge.org', 489 | isUndead: false, 490 | location: { 491 | address: '13223 Sesame Seed Street', 492 | address2: null, 493 | city: 'New London', 494 | stateProvince: 'Melon', 495 | postalCode: '02001-4401' 496 | } 497 | }, 498 | { 499 | firstName: 'India', 500 | middleName: 'Shaman', 501 | lastName: 'Durkin', 502 | phone: '555-998-3322', 503 | altPhone: '554-223-8811', 504 | email: 'indiad@citywire.com', 505 | isUndead: false, 506 | location: { 507 | address: '8899 Circle Circle', 508 | address2: null, 509 | city: 'Kent', 510 | stateProvince: 'Dover', 511 | postalCode: '03001-3300' 512 | } 513 | }, 514 | { 515 | firstName: 'Roo', 516 | middleName: null, 517 | lastName: 'Manga', 518 | phone: '555-667-8811', 519 | altPhone: null, 520 | email: 'rmanga@citywire.com', 521 | isUndead: false, 522 | location: { 523 | address: '1122 London Lane', 524 | address2: null, 525 | city: 'New London', 526 | stateProvince: 'Alcott', 527 | postalCode: '01001-0040' 528 | } 529 | }, //32 530 | { 531 | firstName: 'Roland', 532 | middleName: null, 533 | lastName: 'Cardigan', 534 | phone: '555-898-7716', 535 | altPhone: null, 536 | email: 'rcardigan@citywire.com', 537 | isUndead: false, 538 | location: { 539 | address: '12 Austin Lane', 540 | address2: null, 541 | city: 'New London', 542 | stateProvince: 'Alcott', 543 | postalCode: '01001-3400' 544 | } 545 | }, //33 546 | { 547 | firstName: 'Pao', 548 | middleName: null, 549 | lastName: 'Renoir', 550 | phone: '555-7781-0801', 551 | altPhone: '554-121-8980', 552 | email: 'pren@netforge.org', 553 | isUndead: false, 554 | location: { 555 | address: '1344 Prime Court', 556 | address2: null, 557 | city: 'New London', 558 | stateProvince: 'Melon', 559 | postalCode: '02001-1513' 560 | } 561 | }, 562 | { 563 | firstName: 'Blitz', 564 | middleName: 'Connor', 565 | lastName: 'Macque', 566 | phone: '555-787-1234', 567 | altPhone: null, 568 | email: 'bmacque@citywire.com', 569 | isUndead: false, 570 | location: { 571 | address: '897 Baroque Avenue', 572 | address2: null, 573 | city: 'New London', 574 | stateProvince: 'Alcott', 575 | postalCode: '01001-0013' 576 | } 577 | }, 578 | { 579 | firstName: 'Soldack', 580 | middleName: null, 581 | lastName: 'Trevon', 582 | phone: '555-781-8871', 583 | altPhone: null, 584 | email: 'solty@netforge.org', 585 | isUndead: false, 586 | location: { 587 | address: '23 Saffron Alley', 588 | address2: null, 589 | city: 'New London', 590 | stateProvince: 'Alcott', 591 | postalCode: '01001-0000' 592 | } 593 | }, 594 | { 595 | firstName: 'Lavion', 596 | middleName: null, 597 | lastName: 'Ballastar', 598 | phone: '555-124-7132', 599 | altPhone: null, 600 | email: 'lballastar@citywire.org', 601 | isUndead: false, 602 | location: { 603 | address: '33 Willow Street', 604 | address2: null, 605 | city: 'New London', 606 | stateProvince: 'Melon', 607 | postalCode: '02031-1100' 608 | } 609 | }, 610 | { 611 | firstName: 'Allari', 612 | middleName: 'Semony', 613 | lastName: 'Grulen', 614 | phone: '555-911-8123', 615 | altPhone: null, 616 | email: 'allsemy@netforge.org', 617 | isUndead: false, 618 | location: { 619 | address: '1726 Wanderlust Drive', 620 | address2: 'Apt. 12B', 621 | city: 'New London', 622 | stateProvince: 'Alcott', 623 | postalCode: '01001-0200' 624 | } 625 | }, 626 | { 627 | firstName: 'Cadence', 628 | middleName: null, 629 | lastName: 'Operand', 630 | phone: '555-131-8546', 631 | altPhone: null, 632 | email: 'coperand@citywire.com', 633 | isUndead: false, 634 | location: { 635 | address: '715 Davis Road', 636 | address2: null, 637 | city: 'New London', 638 | stateProvince: 'Melon', 639 | postalCode: '02001-0340' 640 | } 641 | }, 642 | { 643 | firstName: 'Babilar', 644 | middleName: null, 645 | lastName: 'Mancho', 646 | phone: '555-545-1791', 647 | altPhone: null, 648 | email: 'bman@netforge.org', 649 | isUndead: false, 650 | location: { 651 | address: '2212 Wrangler Way', 652 | address2: null, 653 | city: 'New London', 654 | stateProvince: 'Alcott', 655 | postalCode: '01011-4000' 656 | } 657 | } 658 | ]; 659 | 660 | export { people }; 661 | -------------------------------------------------------------------------------- /src/app/db/version.ts: -------------------------------------------------------------------------------- 1 | let version = [ 2 | {id: 1, name: '0.0.7'} 3 | ]; 4 | 5 | export { version } 6 | -------------------------------------------------------------------------------- /src/app/domain/chapter-location.ts: -------------------------------------------------------------------------------- 1 | import { Location } from './location'; 2 | 3 | export class ChapterLocation extends Location { 4 | entryPoints: number = null; 5 | floors: number = null; 6 | hasBasement: boolean = false; 7 | rooftopAccess: boolean = false; 8 | 9 | constructor( chapterLocationData?: any ) { 10 | super( chapterLocationData ); 11 | if( chapterLocationData ) { 12 | let props = Object.keys( this ); 13 | for( let p in props ) { 14 | if( chapterLocationData[ props[p] ] ) { 15 | this[ props[p] ] = chapterLocationData[ props[p] ]; 16 | } 17 | } 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/app/domain/chapter-member.ts: -------------------------------------------------------------------------------- 1 | import { Person } from './person'; 2 | 3 | 4 | export class ChapterMember extends Person { 5 | id: number = null; 6 | chapterId: number = null; 7 | startDate: Date = null; 8 | endDate: Date = null; 9 | isActive: boolean = false; 10 | 11 | constructor( memberData?: any ) { 12 | super( memberData ); 13 | if( memberData ) { 14 | let props = Object.keys( this ); 15 | for( let p in props ) { 16 | if( memberData[ props[p] ] ) { 17 | this[ props[p] ] = memberData[ props[p] ]; 18 | } 19 | } 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/app/domain/chapter.ts: -------------------------------------------------------------------------------- 1 | import { ChapterLocation } from './chapter-location'; 2 | import { Validatable, PropertyValidations } from '../vadacl/interfaces'; 3 | 4 | export class Chapter implements Validatable{ 5 | id: number = null; 6 | guildId: number = null; 7 | name: string = null; 8 | location: ChapterLocation = new ChapterLocation(); 9 | headChapter: boolean = false; 10 | founded: Date = null; 11 | defenses: Number[] = []; 12 | 13 | validations: { [ index: string ] : PropertyValidations } = { 14 | name: { 15 | required: { message: 'The name is required.'}, 16 | pattern: { pattern: '[a-zA-Z]+', message: 'The chapter name cannot contain numbers or spaces.' }, 17 | }, 18 | guild: { required: { } }, 19 | headChapter: { required: { message: 'Must denote if this chapter is the head chapter.' } }, 20 | }; 21 | 22 | constructor( chapterData?: any ) { 23 | 24 | if( chapterData ) { 25 | let props = Object.keys( this ); 26 | for( let p in props ) { 27 | if( chapterData[ props[p] ] ) { 28 | if( props[p] == 'location' ) { 29 | this.location = new ChapterLocation( chapterData.location ) 30 | } else { 31 | this[ props[p] ] = chapterData[ props[p] ]; 32 | } 33 | } 34 | } 35 | 36 | } 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/app/domain/customer.ts: -------------------------------------------------------------------------------- 1 | import { Person } from './person'; 2 | 3 | export class Customer extends Person { 4 | id: number = null; 5 | rating: number = null; 6 | isBanned: boolean = false; 7 | 8 | constructor( customerData?: any ) { 9 | super( customerData ); 10 | if( customerData ) { 11 | let props = Object.keys( this ); 12 | for( let p in props ) { 13 | if( customerData[ props[p] ] ) { 14 | this[ props[p] ] = customerData[ props[p] ]; 15 | } 16 | } 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/app/domain/guild.ts: -------------------------------------------------------------------------------- 1 | export class Guild { 2 | id: number = null; 3 | name: string = null; 4 | email: string = null; 5 | incorporationYear: number = null; 6 | 7 | expenses: number = 0; 8 | revenue: number = 0; 9 | profit: number = 0; 10 | 11 | constructor( guildData?: any ) { 12 | if( guildData ) { 13 | let props = Object.keys( this ); 14 | for( let p in props ) { 15 | if( guildData[ props[p] ] ) { 16 | this[ props[p] ] = guildData[ props[p] ]; 17 | } 18 | } 19 | this.profit = this.calculateProfit(); 20 | } 21 | } 22 | 23 | calculateProfit() { 24 | return this.revenue - this.expenses; 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/app/domain/http-response.ts: -------------------------------------------------------------------------------- 1 | export class HttpResponse { 2 | httpStatus: number; 3 | httpData: any; 4 | 5 | ok: boolean; 6 | data: any = {}; 7 | errors: string[] = []; 8 | 9 | constructor( response?: any ) { 10 | this.httpStatus = response.status; 11 | this.httpData = response.data ? response.data : null; 12 | this.ok = response.ok ? response.ok : false; //ok is true for all 2xx codes 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/app/domain/location.ts: -------------------------------------------------------------------------------- 1 | export class Location { 2 | address: string = null; 3 | address2: string = null; 4 | city: string = null; 5 | stateProvince: string = null; 6 | postalCode: string = null; 7 | 8 | constructor( locationData?: any ) { 9 | if( locationData ) { 10 | let props = Object.keys( this ); 11 | for( let p in props ) { 12 | if( locationData[ props[p] ] ) { 13 | this[ props[p] ] = locationData[ props[p] ]; 14 | } 15 | } 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/app/domain/person.ts: -------------------------------------------------------------------------------- 1 | import { Location } from './location'; 2 | 3 | export class Person { 4 | firstName: string = null; 5 | middleName: string = null; 6 | lastName: string = null; 7 | phone: string = null; 8 | altPhone: string = null; 9 | email: string = null; 10 | isUndead: boolean = false; 11 | residence: Location = new Location(); 12 | 13 | constructor( personData?: any ) { 14 | if( personData ) { 15 | let props = Object.keys( this ); 16 | for( let p in props ) { 17 | if( personData[ props[p] ] ) { 18 | this[ props[p] ] = personData[ props[p] ]; 19 | } 20 | } 21 | if( personData.location ) { 22 | this.residence = new Location( personData.location ) 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/app/environment.ts: -------------------------------------------------------------------------------- 1 | // The file for the current environment will overwrite this one during build 2 | // Different environments can be found in config/environment.{dev|prod}.ts 3 | // The build system defaults to the dev environment 4 | 5 | export const environment = { 6 | production: false 7 | }; 8 | -------------------------------------------------------------------------------- /src/app/guild.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | 3 | import { Http, Headers } from '@angular/http'; 4 | 5 | import { HttpResponse } from './domain/http-response'; 6 | import { Guild } from './domain/guild'; 7 | 8 | import 'rxjs/add/operator/toPromise'; 9 | 10 | @Injectable() 11 | export class GuildService { 12 | 13 | private guildUrl = 'app/guilds'; 14 | 15 | constructor( private http: Http ) { } 16 | 17 | getGuilds() { 18 | return this.http.get( this.guildUrl ) 19 | .toPromise() 20 | .then( response => { 21 | let serviceResponse = new HttpResponse( response ); 22 | serviceResponse.data = response.json().data; 23 | return serviceResponse; 24 | }) 25 | .catch( error => { 26 | let serviceResponse = new HttpResponse( error ); 27 | return serviceResponse; 28 | }); 29 | } 30 | 31 | getGuild( id: number ) { 32 | let selectedGuildUrl = this.guildUrl + `/${id}`; 33 | return this.http.get( selectedGuildUrl ) 34 | .toPromise() 35 | .then( response => { 36 | let serviceResponse = new HttpResponse( response ); 37 | serviceResponse.data.guild = new Guild( response.json().data ); 38 | return serviceResponse; 39 | }) 40 | .catch( error => { 41 | let serviceResponse = new HttpResponse( error ); 42 | //In case the user has a URL bookmarked that points to a deleted guild 43 | if( error.status == 404 ) { 44 | serviceResponse.errors.push( `Selected guild (${id}) does not exist.` ); 45 | } else { 46 | serviceResponse.errors.push( 'An error occurred. Please try again.' ); 47 | } 48 | return serviceResponse; 49 | }); 50 | } 51 | 52 | saveGuild( guild: Guild ) { 53 | if( guild.id ) { 54 | return this.updateGuild( guild ); 55 | } else { 56 | return this.createGuild( guild ); 57 | } 58 | } 59 | 60 | private createGuild( guild: Guild ) { 61 | return this.http 62 | .post( this.guildUrl, JSON.stringify( guild ), { headers: this.getHeaders() }) 63 | .toPromise() 64 | .then( response => { 65 | let serviceResponse = new HttpResponse( response ); 66 | serviceResponse.data.guild = new Guild( response.json().data ); 67 | return serviceResponse; 68 | }) 69 | .catch( error => { 70 | let serviceResponse = new HttpResponse( error ); 71 | if( !serviceResponse.ok ) { 72 | serviceResponse.errors.push( 'An error occurred. Please try again.' ); 73 | } 74 | return serviceResponse; 75 | }); 76 | } 77 | 78 | 79 | private updateGuild( guild: Guild ) { 80 | let url = `${this.guildUrl}/${guild.id}`; 81 | 82 | return this.http 83 | .put( url, JSON.stringify( guild ), { headers: this.getHeaders() } ) 84 | .toPromise() 85 | .then( response => { 86 | let serviceResponse = new HttpResponse( response ); 87 | serviceResponse.data.guild = guild; 88 | return serviceResponse; 89 | }) 90 | .catch( error => { 91 | let serviceResponse = new HttpResponse( error ); 92 | if( !serviceResponse.ok ) { 93 | serviceResponse.errors.push( 'An error occurred. Please try again.' ); 94 | } 95 | return serviceResponse; 96 | }); 97 | } 98 | 99 | private getHeaders(): Headers { 100 | let headers = new Headers(); 101 | headers.append( 'Content-Type', 'application/json' ); 102 | return headers; 103 | } 104 | 105 | private handleError(error: any) { 106 | console.error('An error occurred', error); 107 | return Promise.reject(error.message || error); 108 | } 109 | 110 | } 111 | -------------------------------------------------------------------------------- /src/app/guilds-detail/guilds-detail.component.css: -------------------------------------------------------------------------------- 1 | div.alert-danger { 2 | padding: 8px; 3 | } 4 | 5 | div.alert-danger ul { 6 | list-style-type: none; 7 | margin-left: 0px; 8 | padding-left: 0px; 9 | } 10 | -------------------------------------------------------------------------------- /src/app/guilds-detail/guilds-detail.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
Loading...
4 |

5 | {{(guild.id ? 'Edit' : 'Add' )}} {{(guild.name ? guild.name : 'Guild')}}

6 |
7 |
8 | 9 | 10 |
11 |
12 |
13 |

Error(s):

14 |
    15 |
  • 16 | {{error}} 17 |
  • 18 |
19 |
20 | 21 |
22 |
23 |
24 | 25 |
26 | 27 |
28 | 29 |
30 | 31 |
32 |
    33 |
  • 34 | {{error}} 35 |
  • 36 |
37 |
38 |
39 | 40 |
41 | 42 |
43 | 44 |
45 | 46 |
47 |
    48 |
  • 49 | {{error}} 50 |
  • 51 |
52 |
53 |
54 |
55 | 56 |
57 | 58 |
59 | 60 |
61 |
    62 |
  • 63 | {{error}} 64 |
  • 65 |
66 |
67 |
68 |
69 |
70 |
71 | 72 | 73 |
74 |
75 | 76 |
77 |
78 |
79 | 80 | 81 | -------------------------------------------------------------------------------- /src/app/guilds-detail/guilds-detail.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { ActivatedRoute, Params } from '@angular/router'; 3 | import { GuildService } from '../guild.service'; 4 | import { Guild } from '../domain/guild'; 5 | import { HttpResponse } from '../domain/http-response'; 6 | 7 | @Component({ 8 | moduleId: module.id, 9 | selector: 'app-guilds-detail', 10 | templateUrl: 'guilds-detail.component.html', 11 | styleUrls: ['guilds-detail.component.css'] 12 | }) 13 | export class GuildsDetailComponent implements OnInit { 14 | 15 | guild: Guild; 16 | status: any = { 17 | name: { errors: []}, 18 | incorporationYear: { errors: [] }, 19 | email: { errors: [] } 20 | }; 21 | 22 | serviceErrors: string[]; 23 | 24 | constructor( 25 | private guildService: GuildService, 26 | private route: ActivatedRoute 27 | ) { } 28 | 29 | ngOnInit() { 30 | this.route.params.forEach( (params: Params ) => { 31 | let id = params['id'] ? +params['id'] : null ; //converts param string to number 32 | if( id ) { 33 | this.guildService.getGuild( id ) 34 | .then( ( serviceResponse: HttpResponse ) => { 35 | if( serviceResponse.ok ) { 36 | this.guild = serviceResponse.data.guild; 37 | } else { 38 | this.serviceErrors = serviceResponse.errors; 39 | } 40 | }); 41 | } else { 42 | this.guild = new Guild(); 43 | } 44 | }) 45 | } 46 | 47 | checkFix( propertyName: string ) { 48 | if( this.status[ propertyName ].errors.length > 0 ) { 49 | this.checkValidity( propertyName ); 50 | } 51 | } 52 | 53 | isFormInvalid() { 54 | let formInvalid = false; 55 | for( let property in this.status ) { 56 | if( this.status[ property ].errors.length > 0 ) { 57 | formInvalid = true; 58 | break; 59 | } 60 | } 61 | return formInvalid; 62 | } 63 | 64 | checkValidity( propertyName: string ) { 65 | 66 | let yearRegEx = /[1-2]\d{3}$/; 67 | let emailRegEx = /[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,3}$/; 68 | 69 | switch( propertyName ) { 70 | case 'name': 71 | this.status.name.errors = []; 72 | if( !this.guild[ propertyName ] ) { 73 | this.status.name.errors.push( 'The name field is required.' ); 74 | break; 75 | } 76 | if( this.guild[ propertyName ].length < 5 ) { 77 | this.status.name.errors.push( 'The guild name is too short.' ); 78 | } 79 | break; 80 | case 'incorporationYear': 81 | this.status.incorporationYear.errors = []; 82 | if( !this.guild[ propertyName ] ) { 83 | this.status.incorporationYear.errors.push( 'The year of incorporation is required.' ); 84 | break; 85 | } 86 | if( isNaN( +this.guild[ propertyName ] ) ) { 87 | this.status.incorporationYear.errors.push( 'The incorporation year must be a number.' ); 88 | } else { 89 | if( !yearRegEx.test( this.guild[ propertyName ] ) ) { 90 | this.status.incorporationYear.errors.push( 'The incorporation year must a valid 4-digit year (1xxx or 2xxx).' ); 91 | } 92 | } 93 | break; 94 | case 'email': 95 | this.status.email.errors = []; 96 | if( !emailRegEx.test( this.guild[ propertyName ] ) ) { 97 | this.status.email.errors.push( 'Please enter a valid email address.' ); 98 | } 99 | break; 100 | } 101 | 102 | } 103 | 104 | goBack() { 105 | window.history.back(); 106 | } 107 | 108 | submitForm() { 109 | this.serviceErrors = null; 110 | for( let property in this.status ) { 111 | this.checkValidity( property ); 112 | } 113 | if( !this.isFormInvalid() ) { 114 | this.guildService 115 | .saveGuild( this.guild ) 116 | .then( ( serviceResponse: HttpResponse ) => { 117 | if( serviceResponse.ok ) { 118 | this.guild = serviceResponse.data.guild; 119 | window.history.back(); 120 | } else { 121 | this.serviceErrors = serviceResponse.errors; 122 | } 123 | }); 124 | } 125 | } 126 | 127 | clearForm() { 128 | this.guild.name = null; 129 | this.guild.incorporationYear = null ; 130 | this.guild.email = null; 131 | for( let property in this.status ) { 132 | this.status[ property ].errors = []; 133 | } 134 | } 135 | 136 | } 137 | -------------------------------------------------------------------------------- /src/app/guilds-detail/index.ts: -------------------------------------------------------------------------------- 1 | export * from './guilds-detail.component'; 2 | -------------------------------------------------------------------------------- /src/app/guilds-master/guilds-master.component.css: -------------------------------------------------------------------------------- 1 | .grBrand { 2 | font-family: "American Typewriter"; 3 | font-weight: bold; 4 | } 5 | -------------------------------------------------------------------------------- /src/app/guilds-master/guilds-master.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |

Guilds

4 |

Add guild

5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 |
IDNameIncorporatedExpensesRevenueProfitEmailActions
{{guild.id}}{{guild.name}}{{guild.incorporationYear}}{{guild.expenses | currency:USD:true:'.2-2' }}{{guild.revenue | currency:USD:true:'.2-2' }}{{guild.profit | currency:USD:true:'.2-2'}}{{guild.email}}Edit
31 |
32 |
33 | -------------------------------------------------------------------------------- /src/app/guilds-master/guilds-master.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { GuildService } from '../guild.service'; 3 | import { Guild } from '../domain/guild'; 4 | import { HttpResponse } from "../domain/http-response"; 5 | 6 | @Component({ 7 | moduleId: module.id, 8 | selector: 'app-guilds-master', 9 | templateUrl: 'guilds-master.component.html', 10 | styleUrls: ['guilds-master.component.css'] 11 | }) 12 | export class GuildsMasterComponent implements OnInit { 13 | 14 | guilds: Guild[] = []; 15 | 16 | constructor( private guildService: GuildService ) { } 17 | 18 | ngOnInit() { 19 | this.guildService.getGuilds().then( (httpResponse:HttpResponse) => { 20 | httpResponse.data.forEach( guild => { 21 | this.guilds.push( new Guild( guild ) ) 22 | }) 23 | } ); 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/app/guilds-master/index.ts: -------------------------------------------------------------------------------- 1 | export * from './guilds-master.component'; 2 | -------------------------------------------------------------------------------- /src/app/home/home.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcswartz/angular2-sandbox-guildrunner/c57c5ff1083b1b6ae5a1b6d5ae93adc9e547efa8/src/app/home/home.component.css -------------------------------------------------------------------------------- /src/app/home/home.component.html: -------------------------------------------------------------------------------- 1 |

2 | This space for rent. 3 |

4 | -------------------------------------------------------------------------------- /src/app/home/home.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | moduleId: module.id, 5 | selector: 'app-home', 6 | templateUrl: 'home.component.html', 7 | styleUrls: ['home.component.css'] 8 | }) 9 | export class HomeComponent { 10 | 11 | } 12 | -------------------------------------------------------------------------------- /src/app/home/index.ts: -------------------------------------------------------------------------------- 1 | export * from './home.component'; 2 | -------------------------------------------------------------------------------- /src/app/in-memory-data.service.ts: -------------------------------------------------------------------------------- 1 | import { version } from './db/version'; 2 | import { guilds } from './db/guilds'; 3 | import { defenseMeasures } from './db/defense-measures'; 4 | import { chapters } from './db/chapters'; 5 | import { chapterMembers } from './db/chapter-members'; 6 | 7 | export class InMemoryDataService { 8 | createDb() { 9 | 10 | return { 11 | version, 12 | guilds, 13 | defenseMeasures, 14 | chapters, 15 | chapterMembers 16 | }; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/app/index.ts: -------------------------------------------------------------------------------- 1 | export * from './environment'; 2 | export * from './app.component'; 3 | -------------------------------------------------------------------------------- /src/app/main-navigation/index.ts: -------------------------------------------------------------------------------- 1 | export * from './main-navigation.component'; 2 | -------------------------------------------------------------------------------- /src/app/main-navigation/main-navigation.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcswartz/angular2-sandbox-guildrunner/c57c5ff1083b1b6ae5a1b6d5ae93adc9e547efa8/src/app/main-navigation/main-navigation.component.css -------------------------------------------------------------------------------- /src/app/main-navigation/main-navigation.component.html: -------------------------------------------------------------------------------- 1 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /src/app/main-navigation/main-navigation.component.spec.ts: -------------------------------------------------------------------------------- 1 | /* tslint:disable:no-unused-variable */ 2 | 3 | import { By } from '@angular/platform-browser'; 4 | import { DebugElement } from '@angular/core'; 5 | import { addProviders, async, inject } from '@angular/core/testing'; 6 | import { MainNavigationComponent } from './main-navigation.component'; 7 | 8 | describe('Component: MainNavigation', () => { 9 | it('should create an instance', () => { 10 | let component = new MainNavigationComponent(); 11 | expect(component).toBeTruthy(); 12 | }); 13 | }); 14 | -------------------------------------------------------------------------------- /src/app/main-navigation/main-navigation.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | moduleId: module.id, 5 | selector: 'app-main-navigation', 6 | templateUrl: 'main-navigation.component.html', 7 | styleUrls: ['main-navigation.component.css'] 8 | }) 9 | export class MainNavigationComponent { 10 | 11 | } 12 | -------------------------------------------------------------------------------- /src/app/member.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { Http, Headers } from '@angular/http'; 3 | 4 | import { HttpResponse } from './domain/http-response'; 5 | import { ChapterMember } from './domain/chapter-member'; 6 | 7 | import 'rxjs/add/operator/toPromise'; 8 | 9 | @Injectable() 10 | export class MemberService { 11 | 12 | private memberUrl = 'app/chapterMembers'; 13 | 14 | constructor( private http: Http ) { } 15 | 16 | getMembers() { 17 | return this.http.get( this.memberUrl ) 18 | .toPromise() 19 | .then( response => { 20 | let serviceResponse = new HttpResponse( response ); 21 | serviceResponse.data = response.json().data; 22 | return serviceResponse; 23 | }) 24 | .catch( error => { 25 | let serviceResponse = new HttpResponse( error ); 26 | return serviceResponse; 27 | }); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/app/members-master/index.ts: -------------------------------------------------------------------------------- 1 | export * from './members-master.component'; 2 | -------------------------------------------------------------------------------- /src/app/members-master/members-master.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcswartz/angular2-sandbox-guildrunner/c57c5ff1083b1b6ae5a1b6d5ae93adc9e547efa8/src/app/members-master/members-master.component.css -------------------------------------------------------------------------------- /src/app/members-master/members-master.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |

Chapter Members

4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 |
IDFirst NameLast NameGuildChapterActive?
{{member.id}}{{member.firstName}}{{member.lastName}}{{guilds[chapters[member.chapterId].guildId].name}}{{chapters[member.chapterId].name}}{{member.isActive ? 'Yes' : 'No'}}
26 |
27 |
28 | -------------------------------------------------------------------------------- /src/app/members-master/members-master.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { MemberService } from '../member.service'; 3 | import { ChapterService } from '../chapter.service'; 4 | import { GuildService } from '../guild.service'; 5 | import { ChapterMember } from '../domain/chapter-member'; 6 | import { HttpResponse } from '../domain/http-response'; 7 | 8 | @Component({ 9 | moduleId: module.id, 10 | selector: 'app-members-master', 11 | templateUrl: 'members-master.component.html', 12 | styleUrls: ['members-master.component.css'] 13 | }) 14 | export class MembersMasterComponent implements OnInit { 15 | 16 | members: ChapterMember[] = []; 17 | chapters: any = {}; 18 | guilds: any = {}; 19 | 20 | constructor( 21 | private memberService: MemberService, 22 | private chapterService: ChapterService, 23 | private guildService: GuildService 24 | ) { } 25 | 26 | ngOnInit() { 27 | 28 | Promise.all( [ 29 | this.memberService.getMembers(), 30 | this.chapterService.getChapters(), 31 | this.guildService.getGuilds() 32 | ]).then( (results:Promise[]) => { 33 | results[0]['data'].forEach( memberData => { 34 | this.members.push( new ChapterMember( memberData ) ) 35 | }); 36 | results[1]['data'].forEach( chapterData => { 37 | this.chapters[ chapterData.id ] = chapterData 38 | }); 39 | results[2]['data'].forEach( guildData => { 40 | this.guilds[ guildData.id ] = guildData 41 | }); 42 | }); 43 | 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /src/app/sandbox/chapter-list/chapter-list.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcswartz/angular2-sandbox-guildrunner/c57c5ff1083b1b6ae5a1b6d5ae93adc9e547efa8/src/app/sandbox/chapter-list/chapter-list.component.css -------------------------------------------------------------------------------- /src/app/sandbox/chapter-list/chapter-list.component.html: -------------------------------------------------------------------------------- 1 |

List of all chapters from data:

2 |
{{chapterList}}
3 | -------------------------------------------------------------------------------- /src/app/sandbox/chapter-list/chapter-list.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { SandboxService } from '../sandbox.service'; 3 | 4 | @Component({ 5 | moduleId: module.id, 6 | selector: 'app-chapter-list', 7 | templateUrl: 'chapter-list.component.html', 8 | styleUrls: ['chapter-list.component.css'] 9 | }) 10 | export class ChapterListComponent implements OnInit { 11 | 12 | chapterList; 13 | 14 | constructor( private sandboxService: SandboxService ) { } 15 | 16 | ngOnInit() { 17 | this.sandboxService.getChapters().then( chapters => this.chapterList = JSON.stringify( chapters, null, 2 ) ); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/app/sandbox/chapter-list/index.ts: -------------------------------------------------------------------------------- 1 | export * from './chapter-list.component'; 2 | -------------------------------------------------------------------------------- /src/app/sandbox/chapter-member-list/chapter-member-list.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcswartz/angular2-sandbox-guildrunner/c57c5ff1083b1b6ae5a1b6d5ae93adc9e547efa8/src/app/sandbox/chapter-member-list/chapter-member-list.component.css -------------------------------------------------------------------------------- /src/app/sandbox/chapter-member-list/chapter-member-list.component.html: -------------------------------------------------------------------------------- 1 |

List of all chapter members from data:

2 |
{{memberList}}
3 | -------------------------------------------------------------------------------- /src/app/sandbox/chapter-member-list/chapter-member-list.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { SandboxService } from '../sandbox.service'; 3 | 4 | @Component({ 5 | moduleId: module.id, 6 | selector: 'app-chapter-member-list', 7 | templateUrl: 'chapter-member-list.component.html', 8 | styleUrls: ['chapter-member-list.component.css'] 9 | }) 10 | export class ChapterMemberListComponent implements OnInit { 11 | 12 | memberList; 13 | 14 | constructor( private sandboxService: SandboxService ) { } 15 | 16 | ngOnInit() { 17 | this.sandboxService.getChapterMembers().then( members => this.memberList = JSON.stringify( members, null, 2 ) ); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/app/sandbox/chapter-member-list/index.ts: -------------------------------------------------------------------------------- 1 | export * from './chapter-member-list.component'; 2 | -------------------------------------------------------------------------------- /src/app/sandbox/chapter-reactive-form/chapter-reactive-form.component.css: -------------------------------------------------------------------------------- 1 | div.alert-danger { 2 | padding: 8px; 3 | } 4 | 5 | ul { 6 | list-style-type: none; 7 | margin-left: 0px; 8 | padding-left: 0px; 9 | } 10 | 11 | .form-group { 12 | padding-bottom:7px; 13 | } 14 | 15 | .rawErrors { 16 | border: 1px solid #999; 17 | margin-top:6px; 18 | padding:4px; 19 | } 20 | -------------------------------------------------------------------------------- /src/app/sandbox/chapter-reactive-form/chapter-reactive-form.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
Loading...
4 |

Edit {{chapter.name}}

5 |
6 |
7 | 8 |
9 |

Chapter model values are updated on submit.

10 |
11 | 12 |
13 | 14 |
15 |
    16 |
  • 17 | {{error}} 18 |
  • 19 |
20 |
21 | 22 |
23 | Raw Validator errors:
24 | {{ form.controls.name.errors | json }} 25 |
26 |
27 |
28 | Form control state:
29 | Valid: {{form.controls.name.valid}}
30 | Pristine: {{form.controls.name.pristine}}
31 | Touched: {{form.controls.name.touched}}
32 |
33 |
34 | Model value:
35 | {{chapter.name}} 36 |
37 |
38 | 39 |
40 | 41 |
42 | 46 |
47 |
    48 |
  • 49 | {{error}} 50 |
  • 51 |
52 |
53 | 54 |
55 | Raw Validator errors:
56 | {{ form.controls.guild.errors | json }} 57 |
58 |
59 |
60 | Form control state:
61 | Valid: {{form.controls.guild.valid}}
62 | Pristine: {{form.controls.guild.pristine}}
63 | Touched: {{form.controls.guild.touched}}
64 |
65 |
66 | Model value:
67 | {{chapter.guildId}} (Name: {{ guildArray[ ( chapter.guildId - 1 )].name }}) 68 |
69 |
70 | 71 |
72 | 73 |
74 | Yes    75 | No 76 | (value: {{form.controls.headChapter.value}})
77 | 78 |
79 |
    80 |
  • 81 | {{error}} 82 |
  • 83 |
84 |
85 | 86 |
87 | Raw Validator errors:
88 | {{ form.controls.headChapter.errors | json }} 89 |
90 |
91 |
92 | Form control state:
93 | Valid: {{form.controls.headChapter.valid}}
94 | Pristine: {{form.controls.headChapter.pristine}}
95 | Touched: {{form.controls.headChapter.touched}}
96 |
97 |
98 | Model value:
99 | {{chapter.headChapter}} 100 |
101 |
102 | 103 |
104 | 105 |
106 |
    107 |
  • 108 | {{defenseArray[i].label}} 109 | (value: {{form.controls.defenses.controls[i].value}}) 110 |
  • 111 |
112 |
113 |
    114 |
  • 115 | {{error}} 116 |
  • 117 |
118 |
119 | 120 |
121 | Raw Validator errors:
122 | {{ form.controls.defenses.errors | json }} 123 |
124 |
125 |
126 | Form control state:
127 | Valid: {{form.controls.defenses.valid}}
128 | Pristine: {{form.controls.defenses.pristine}}
129 | Touched: {{form.controls.defenses.touched}}
130 |
131 |
132 | Model value:
133 | {{chapter.defenses | json}} 134 |
135 |
136 | 137 |
138 |
139 | 140 | 141 |
142 |
143 | 144 |
145 |
146 |
147 | -------------------------------------------------------------------------------- /src/app/sandbox/chapter-reactive-form/chapter-reactive-form.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { Chapter } from "../../domain/chapter"; 3 | import { guilds } from "../../db/guilds"; 4 | import { defenseMeasures } from "../../db/defense-measures"; 5 | 6 | import { FormControl, FormGroup, FormArray, FormBuilder } from '@angular/forms'; 7 | import { Vadacl } from "../../vadacl/vadacl"; 8 | 9 | @Component({ 10 | moduleId: module.id, 11 | selector: 'app-chapter-reactive-form', 12 | templateUrl: 'chapter-reactive-form.component.html', 13 | styleUrls: ['chapter-reactive-form.component.css'] 14 | }) 15 | export class ChapterReactiveFormComponent extends Vadacl implements OnInit { 16 | 17 | chapter: Chapter; 18 | defenseArray: any = []; 19 | guildArray: any = []; 20 | defenseBoxArray: FormArray; 21 | 22 | pageLoaded: boolean = false; 23 | 24 | form: FormGroup; 25 | 26 | constructor( private formBuilder: FormBuilder ) { 27 | super(); 28 | } 29 | 30 | ngOnInit() { 31 | this.initializeData(); 32 | this.buildForm(); 33 | this.pageLoaded = true 34 | } 35 | 36 | buildForm() { 37 | 38 | //Create a custom Validator function for the defenses array 39 | function hasDefenses( formArray: FormArray) { 40 | let valid = false; 41 | for( let c in formArray.controls ) { 42 | if( formArray.controls[c].value == true ) { valid = true } 43 | } 44 | return valid == true ? null : { 'noDefenses': { 'noDefenses': true, 'message': 'Chapter must have at least one defense.' } } 45 | } 46 | 47 | //Construct and populate the defenses FormArray outside of the FormBuilder so we can populate it dynamically 48 | this.defenseBoxArray = new FormArray( [], hasDefenses ); 49 | for( let d in this.defenseArray ) { 50 | this.defenseBoxArray.push( new FormControl(( this.chapter.defenses.indexOf( this.defenseArray[d].id ) > -1 ))) 51 | } 52 | 53 | this.form = this.formBuilder.group( { 54 | 'name': [ 55 | this.chapter.name, 56 | this.applyRules( 57 | this.chapter, 58 | 'name', 59 | { minLength: { minLength: 4, message: 'The name must be at least 4 characters.' } } 60 | ) 61 | ], 62 | 'guild': [ 63 | this.chapter.guildId, 64 | this.applyRules( this.chapter, 'guild' ) 65 | ], 66 | 'headChapter': [ 67 | this.chapter.headChapter, 68 | this.applyRules( this.chapter, 'headChapter' ) 69 | ], 70 | 'defenses': this.defenseBoxArray 71 | } ); 72 | 73 | } 74 | 75 | submitForm() { 76 | if( this.form.valid ) { 77 | this.chapter.name = this.form.value.name; //value is a key/value map 78 | this.chapter.guildId = +this.form.value.guild; //need this translated to number, hence + 79 | this.chapter.headChapter = this.form.value.headChapter === "true"; 80 | this.chapter.defenses = []; 81 | for( let db in this.defenseBoxArray.controls ) { 82 | if( this.defenseBoxArray.controls[ db ].value == true ) { 83 | this.chapter.defenses.push( this.defenseArray[ db ].id ) 84 | } 85 | } 86 | } 87 | } 88 | 89 | resetForm() { 90 | this.form.reset(); 91 | } 92 | 93 | changeName() { 94 | this.changeControlValue( this.form.controls[ 'name' ], '999' ); 95 | } 96 | 97 | initializeData() { 98 | this.chapter = new Chapter( { 99 | id: 99, 100 | guildId: 2, 101 | name: 'Lobbyists', 102 | headChapter: null, 103 | founded: new Date(), 104 | defenses: [ 1, 3 ], 105 | location: { 106 | address: '12 Main Street', 107 | city: 'New London', 108 | stateProvince: 'Arkin', 109 | postalCode: '89000-8901', 110 | entryPoints: 2, 111 | floors: 3, 112 | hasBasement: false, 113 | rooftopAccess: true 114 | } 115 | }); 116 | 117 | guilds.forEach( guild => { 118 | this.guildArray.push( guild ); 119 | }); 120 | 121 | defenseMeasures.forEach( defense => { 122 | this.defenseArray.push( defense ); 123 | }); 124 | } 125 | 126 | } 127 | -------------------------------------------------------------------------------- /src/app/sandbox/chapter-reactive-form/index.ts: -------------------------------------------------------------------------------- 1 | export * from './chapter-reactive-form.component'; 2 | -------------------------------------------------------------------------------- /src/app/sandbox/guild-list/guild-list.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcswartz/angular2-sandbox-guildrunner/c57c5ff1083b1b6ae5a1b6d5ae93adc9e547efa8/src/app/sandbox/guild-list/guild-list.component.css -------------------------------------------------------------------------------- /src/app/sandbox/guild-list/guild-list.component.html: -------------------------------------------------------------------------------- 1 |

List of all guilds from data:

2 |
{{guildList}}
3 | 4 | -------------------------------------------------------------------------------- /src/app/sandbox/guild-list/guild-list.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { SandboxService } from '../sandbox.service'; 3 | 4 | @Component({ 5 | moduleId: module.id, 6 | selector: 'app-guild-list', 7 | templateUrl: 'guild-list.component.html', 8 | styleUrls: ['guild-list.component.css'] 9 | }) 10 | export class GuildListComponent implements OnInit { 11 | 12 | guildList; 13 | 14 | constructor( private sandboxService: SandboxService ) { } 15 | 16 | ngOnInit() { 17 | this.sandboxService.getGuilds().then( guilds => this.guildList = JSON.stringify( guilds, null, 2 ) ); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/app/sandbox/guild-list/index.ts: -------------------------------------------------------------------------------- 1 | export * from './guild-list.component'; 2 | -------------------------------------------------------------------------------- /src/app/sandbox/sandbox.module.ts: -------------------------------------------------------------------------------- 1 | //Modules and routing imports 2 | import { NgModule } from '@angular/core'; 3 | import { BrowserModule } from '@angular/platform-browser'; 4 | import { sandboxRouting } from './sandbox.routing' 5 | import { ReactiveFormsModule } from '@angular/forms'; 6 | 7 | //Declarations (components, directives, and pipes) 8 | import { GuildListComponent } from "./guild-list/guild-list.component"; 9 | import { ChapterMemberListComponent } from "./chapter-member-list/chapter-member-list.component"; 10 | import { ChapterListComponent } from "./chapter-list/chapter-list.component"; 11 | import { ChapterReactiveFormComponent } from "./chapter-reactive-form/chapter-reactive-form.component"; 12 | 13 | //Providers (services 14 | import { SandboxService } from './sandbox.service'; 15 | 16 | 17 | @NgModule({ 18 | imports: [ 19 | sandboxRouting, 20 | BrowserModule, 21 | ReactiveFormsModule 22 | ], 23 | 24 | declarations: [ 25 | GuildListComponent, 26 | ChapterListComponent, 27 | ChapterMemberListComponent, 28 | ChapterReactiveFormComponent 29 | ], 30 | 31 | providers: [ 32 | SandboxService 33 | ] 34 | }) 35 | 36 | export class SandboxModule {} 37 | 38 | 39 | -------------------------------------------------------------------------------- /src/app/sandbox/sandbox.routing.ts: -------------------------------------------------------------------------------- 1 | import { Routes, RouterModule } from '@angular/router'; 2 | 3 | import { GuildListComponent} from "./guild-list/guild-list.component"; 4 | import { ChapterListComponent } from "./chapter-list/chapter-list.component"; 5 | import { ChapterMemberListComponent } from "./chapter-member-list/chapter-member-list.component"; 6 | import { ChapterReactiveFormComponent } from "./chapter-reactive-form/chapter-reactive-form.component"; 7 | 8 | 9 | const sandboxRoutes: Routes = [ 10 | { path: 'sandbox-guildlist', component: GuildListComponent }, 11 | { path: 'sandbox-chapterlist', component: ChapterListComponent }, 12 | { path: 'sandbox-memberlist', component: ChapterMemberListComponent}, 13 | { path: 'sandbox-reactivechapter', component: ChapterReactiveFormComponent } 14 | ]; 15 | 16 | export const sandboxRouting = RouterModule.forChild( sandboxRoutes ); 17 | -------------------------------------------------------------------------------- /src/app/sandbox/sandbox.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { Http } from '@angular/http'; 3 | 4 | import 'rxjs/add/operator/toPromise'; 5 | 6 | @Injectable() 7 | export class SandboxService { 8 | 9 | private guildUrl = 'app/guilds'; 10 | private chapterUrl = 'app/chapters'; 11 | private memberUrl = 'app/chapterMembers'; 12 | 13 | constructor( private http: Http) {} 14 | 15 | /* 16 | So this gets the raw data (useful for diagnostic display), but if we type it to the object, then what? 17 | */ 18 | getGuilds() { 19 | return this.http.get( this.guildUrl ) 20 | .toPromise() 21 | .then(response => response.json().data ) 22 | .catch(this.handleError); 23 | } 24 | 25 | getChapters() { 26 | return this.http.get( this.chapterUrl ) 27 | .toPromise() 28 | .then(response => response.json().data ) 29 | .catch(this.handleError); 30 | } 31 | 32 | getChapterMembers() { 33 | return this.http.get( this.memberUrl ) 34 | .toPromise() 35 | .then(response => response.json().data ) 36 | .catch(this.handleError); 37 | } 38 | 39 | 40 | private handleError(error: any) { 41 | console.error('An error occurred', error); 42 | return Promise.reject(error.message || error); 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /src/app/shared/index.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcswartz/angular2-sandbox-guildrunner/c57c5ff1083b1b6ae5a1b6d5ae93adc9e547efa8/src/app/shared/index.ts -------------------------------------------------------------------------------- /src/app/vadacl/interfaces.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Interfaces that can be used by the TypeScript compiler to enforce the proper key/value pairs for the validation options. 3 | */ 4 | interface RequiredSettings { 5 | message ?: string 6 | } 7 | 8 | interface MinLengthSettings { 9 | minLength : number, 10 | message ?: string 11 | } 12 | 13 | interface MaxLengthSettings { 14 | maxLength : number, 15 | message ?: string 16 | } 17 | 18 | interface PatternSettings { 19 | pattern : string, 20 | message ?: string 21 | } 22 | 23 | interface WithinLengthSettings { 24 | minLength : number, 25 | maxLength : number, 26 | message ?: string 27 | } 28 | 29 | /* 30 | Interface for defining any and all known validation methods for a given domain object property 31 | */ 32 | interface PropertyValidations { 33 | required ?: RequiredSettings, 34 | minLength ?: MinLengthSettings, 35 | maxLength ?: MaxLengthSettings, 36 | pattern ?: PatternSettings, 37 | withinLength ?: WithinLengthSettings 38 | } 39 | 40 | /* 41 | Interface that can be implemented by domain classes to enforce the presence of a "validations" property object literal. 42 | */ 43 | interface Validatable { 44 | validations: { [ index: string ]: any }; 45 | } 46 | 47 | export { PropertyValidations, Validatable } 48 | 49 | -------------------------------------------------------------------------------- /src/app/vadacl/messages/messages-en.ts: -------------------------------------------------------------------------------- 1 | let Messages = { 2 | 3 | /* DEFAULT VALIDATOR ERROR MESSAGES */ 4 | required: 'A value is required', 5 | minLength: 'The value is too short.', 6 | maxLength: 'The value is too long.', 7 | pattern: 'The value does not match the pattern.', 8 | withinLength: 'The value does not meet the size requirements', 9 | 10 | }; 11 | 12 | export { Messages }; 13 | 14 | -------------------------------------------------------------------------------- /src/app/vadacl/patterns/patterns-en.ts: -------------------------------------------------------------------------------- 1 | let Patterns = { 2 | /* 3 | Define pattern strings used throughout your application (email, url, etc.). 4 | */ 5 | }; 6 | 7 | export { Patterns } 8 | -------------------------------------------------------------------------------- /src/app/vadacl/vadacl.ts: -------------------------------------------------------------------------------- 1 | 2 | import { AbstractControl, FormGroup, FormArray } from '@angular/forms'; 3 | import { ValidationMethods } from './validation-methods'; 4 | 5 | /* 6 | The Vadacl class can be used as the superclass for a component that implements validation, or as an injected service. 7 | */ 8 | export class Vadacl { 9 | 10 | applyRules(domainClass: any, propertyName: string, validationOverrides ?: any ) : any[] { 11 | let validators: any[] = []; 12 | 13 | //Collect the property validations defined in the domain class (if any). 14 | let propertyValidations = domainClass.validations ? ( domainClass.validations[ propertyName ] || {} ) : {}; 15 | 16 | //Apply any validation overrides and additional validations. 17 | let mergedValidations = this.mergeValidations( propertyValidations, validationOverrides ); 18 | 19 | for( let mv in mergedValidations ) { 20 | //Parse the argument values to apply to the validation method. 21 | let validatorArguments = this.getValidatorArguments( this.getMethodDeclaredArguments( ValidationMethods[ mv ] ), mergedValidations[ mv ] ); 22 | /* 23 | Execute the validation method, which will return a validator that the Angular reactive form classes will 24 | trigger on a value change, and add that validator to the validators array. 25 | */ 26 | validators.push( ValidationMethods[ mv ].apply( null, validatorArguments ) ); 27 | } 28 | 29 | return validators; 30 | } 31 | 32 | /* 33 | Converts function to a string and then uses regular expressions to pull out the argument names. The argument names 34 | are denoted as object literal properties with values equal to their position in the list of arguments (the positions 35 | are needed to help place the validation method argument values in the correct order). 36 | */ 37 | getMethodDeclaredArguments( fn: any ) : any { 38 | let methodDeclarationRegExp = /^function\s*[^\(]*\(\s*([^\)]*)\)/m; 39 | let argumentSplit = /,/; 40 | let stripCommentsRegExp = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg; 41 | 42 | let methodArguments = {}; 43 | let argumentPosition = 0; 44 | 45 | let methodAsString = fn.toString().replace( stripCommentsRegExp, '' ); 46 | let methodDeclaration = methodAsString.match( methodDeclarationRegExp ); 47 | let argumentArray = methodDeclaration[ 1 ].split( argumentSplit ); 48 | 49 | for( let argIndex in argumentArray) { 50 | methodArguments[ argumentArray[ argIndex ].replace(/\s/g,'') ] = argumentPosition++; 51 | } 52 | 53 | return methodArguments; 54 | } 55 | 56 | /* 57 | The arguments passed into the call to the validation method are organized in the proper order based on the order 58 | of the argument names in the validation method. 59 | */ 60 | getValidatorArguments( argumentDeclarations: any, validatorArguments: any ) : any[] { 61 | let executionArguments: any[] = []; 62 | for( let arg in argumentDeclarations ) { 63 | executionArguments[ argumentDeclarations[ arg ] ] = validatorArguments[ arg ] || null; 64 | } 65 | return executionArguments; 66 | } 67 | 68 | /* 69 | Merges the previous validation settings with any new settings. 70 | */ 71 | mergeValidations( baseValidations: any, overrideValidations: any ) : any { 72 | for( let validation in overrideValidations ) { 73 | if( baseValidations[ validation ] == undefined ) { 74 | baseValidations[ validation ] = overrideValidations[ validation ] 75 | } else { 76 | for( let setting in overrideValidations[ validation ] ) { 77 | baseValidations[ validation ][ setting ] = overrideValidations[ validation ][ setting ] 78 | } 79 | } 80 | } 81 | return baseValidations; 82 | } 83 | 84 | /* 85 | Determines whether the errors for the form element should be displayed. By default, returns false 86 | if the element is still marked as untouched. 87 | */ 88 | showErrors( formElement: AbstractControl|FormGroup|FormArray, onlyAfterTouched: boolean = true ) : boolean { 89 | let elementActive = onlyAfterTouched ? formElement.touched : true; 90 | return ( formElement.dirty && formElement.invalid && elementActive ) ? true : false 91 | } 92 | 93 | /* 94 | Returns array of error messages. By default, error messages only returned when control is dirty. 95 | */ 96 | getControlErrors( control: AbstractControl, onlyWhenDirty: boolean = true ) : string[] { 97 | let errorMessages: string[] = []; 98 | if( ( !onlyWhenDirty || control.dirty ) && control.errors ) { 99 | let errorArray = Object.keys( control.errors ); 100 | for ( let err in errorArray ) { 101 | if ( control.errors[ errorArray[ err ] ].message ) { 102 | errorMessages.push( control.errors[ errorArray[ err ] ].message ); 103 | } 104 | } 105 | } 106 | return errorMessages; 107 | } 108 | 109 | /* 110 | Ensures a programmatic change to an AbstractControl value is marked as dirty (and by default as touched) 111 | prior to the change, properly invoking validation and the display of any validation errors. 112 | */ 113 | changeControlValue( control: AbstractControl, value: any, markTouched: boolean = true ) : void { 114 | control.markAsDirty(); 115 | control.markAsTouched( markTouched ); 116 | control.setValue( value ); 117 | } 118 | 119 | } 120 | -------------------------------------------------------------------------------- /src/app/vadacl/validation-methods.ts: -------------------------------------------------------------------------------- 1 | 2 | import { AbstractControl, Validators } from '@angular/forms'; 3 | import { Messages } from './messages/messages-en'; 4 | 5 | /* 6 | The ValidationMethods class contains all of the validation methods defined for use by vadacl. Validation methods 7 | provided in Angular 2 are wrapped and leveraged whenever practical. 8 | */ 9 | export class ValidationMethods { 10 | 11 | //Modeled after the official Angular 2 Required validators value checks 12 | static isEmpty( control: AbstractControl ) { 13 | let v = control.value; 14 | if ( v === undefined || v === null || ( typeof v === 'string' && v == '' ) ) { 15 | return true; 16 | } else { 17 | return false; 18 | } 19 | } 20 | 21 | static required( message ?: string ) { 22 | let msg = message || Messages.required; 23 | return function ( control: AbstractControl ) { 24 | return ValidationMethods.isEmpty( control ) ? { 'required': { 'isEmpty': true, 'message': msg } } : null; 25 | } 26 | } 27 | 28 | static minLength( minLength: number, message ?: string ) { 29 | let msg = message || Messages.minLength; 30 | return function ( control: AbstractControl ) { 31 | //Use and invoke the official Angular 2 minLength Validator 32 | let baseValidator = Validators.minLength( minLength ); 33 | let outcome = baseValidator( control) ; 34 | if ( outcome ) { 35 | //Append the message 36 | outcome[ 'minlength' ].message = msg; 37 | } 38 | return outcome; 39 | } 40 | } 41 | 42 | static maxLength( maxLength: number, message ?: string ) { 43 | let msg = message || Messages.maxLength; 44 | return function ( control: AbstractControl ) { 45 | //Use and invoke the official Angular 2 maxLength Validator 46 | let baseValidator = Validators.maxLength( maxLength ); 47 | let outcome = baseValidator( control) ; 48 | if ( outcome ) { 49 | //Append the message 50 | outcome[ 'maxlength' ].message = msg; 51 | } 52 | return outcome; 53 | } 54 | } 55 | 56 | static pattern( pattern: string, message ?: string ) { 57 | let msg = message || Messages.pattern; 58 | return function ( control: AbstractControl ) { 59 | //Use and invoke the official Angular 2 pattern Validator 60 | let baseValidator = Validators.pattern( pattern ); 61 | let outcome = baseValidator( control) ; 62 | if ( outcome ) { 63 | //Append the message 64 | outcome[ 'pattern' ].message = msg; 65 | } 66 | return outcome; 67 | } 68 | } 69 | 70 | static withinLength( minLength: number, maxLength: number, message ?: string ) { 71 | let msg = message || Messages.withinLength; 72 | return function ( control: AbstractControl ) { 73 | //Do not display if the control is empty 74 | if( ValidationMethods.isEmpty( control ) ){ 75 | return null; 76 | } 77 | let v = control.value; 78 | return v.length < minLength || v.length > maxLength ? 79 | { 'withinlength': { 'minLength': minLength, 'maxLength': maxLength, 'actualLength': v.length, 'message': msg } } : 80 | null 81 | } 82 | } 83 | 84 | } 85 | 86 | 87 | -------------------------------------------------------------------------------- /src/app/version/index.ts: -------------------------------------------------------------------------------- 1 | export * from './version.component'; 2 | -------------------------------------------------------------------------------- /src/app/version/version.component.html: -------------------------------------------------------------------------------- 1 |

Version: {{versionNumber}}

2 | -------------------------------------------------------------------------------- /src/app/version/version.component.spec.ts: -------------------------------------------------------------------------------- 1 | /* tslint:disable:no-unused-variable */ 2 | 3 | import { By } from '@angular/platform-browser'; 4 | import { DebugElement } from '@angular/core'; 5 | import { addProviders, async, inject } from '@angular/core/testing'; 6 | import { VersionComponent } from './version.component'; 7 | import { VersionService } from './version.service'; 8 | import { Http } from '@angular/http'; 9 | 10 | let http = {} as Http; 11 | let versionService = new VersionService( http ); 12 | 13 | describe('Component: Version', () => { 14 | it('should create an instance', () => { 15 | let component = new VersionComponent( versionService ); 16 | expect(component).toBeTruthy(); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /src/app/version/version.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { VersionService } from './version.service'; 3 | 4 | @Component({ 5 | moduleId: module.id, 6 | selector: 'app-version', 7 | templateUrl: 'version.component.html', 8 | }) 9 | export class VersionComponent implements OnInit { 10 | 11 | versionNumber = '-.-.-'; 12 | 13 | constructor( private versionService: VersionService ) { } 14 | 15 | ngOnInit() { 16 | this.versionService.getVersion().then( versions => this.versionNumber = versions[0].name ); 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/app/version/version.service.spec.ts: -------------------------------------------------------------------------------- 1 | /* tslint:disable:no-unused-variable */ 2 | 3 | import { addProviders, async, inject } from '@angular/core/testing'; 4 | import { VersionService } from './version.service'; 5 | import { HTTP_PROVIDERS } from '@angular/http'; 6 | 7 | describe('Service: Version', () => { 8 | beforeEach(() => { 9 | addProviders([VersionService, HTTP_PROVIDERS ]); 10 | }); 11 | 12 | it('should instantiate the service', 13 | inject([VersionService], 14 | (service: VersionService) => { 15 | expect(service).toBeTruthy(); 16 | })); 17 | }); 18 | -------------------------------------------------------------------------------- /src/app/version/version.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { Http } from '@angular/http'; 3 | 4 | import 'rxjs/add/operator/toPromise'; 5 | 6 | @Injectable() 7 | export class VersionService { 8 | 9 | private versionUrl = 'app/version'; 10 | 11 | constructor( private http: Http ) { } 12 | 13 | getVersion() { 14 | return this.http.get(this.versionUrl) 15 | .toPromise() 16 | .then(response => response.json().data ) 17 | .catch(this.handleError); 18 | } 19 | 20 | private handleError(error: any) { 21 | console.error('An error occurred', error); 22 | return Promise.reject(error.message || error); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcswartz/angular2-sandbox-guildrunner/c57c5ff1083b1b6ae5a1b6d5ae93adc9e547efa8/src/favicon.ico -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | GuildRunner 6 | 7 | 8 | {{#unless environment.production}} 9 | 10 | {{/unless}} 11 | 12 | 13 | 14 | 15 | 16 | Loading... 17 | 18 | {{#each scripts.polyfills}} 19 | 20 | {{/each}} 21 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 2 | import { AppModule } from './app/app.module'; 3 | platformBrowserDynamic().bootstrapModule(AppModule); 4 | -------------------------------------------------------------------------------- /src/system-config.ts: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | // SystemJS configuration file, see links for more information 4 | // https://github.com/systemjs/systemjs 5 | // https://github.com/systemjs/systemjs/blob/master/docs/config-api.md 6 | 7 | /*********************************************************************************************** 8 | * User Configuration. 9 | **********************************************************************************************/ 10 | /** Map relative paths to URLs. */ 11 | const map: any = { 12 | 'angular2-in-memory-web-api': 'vendor/angular2-in-memory-web-api' 13 | }; 14 | 15 | /** User packages configuration. */ 16 | const packages: any = { 17 | 'angular2-in-memory-web-api': { main: 'index.js', defaultExtension: 'js' }, 18 | }; 19 | 20 | //////////////////////////////////////////////////////////////////////////////////////////////// 21 | /*********************************************************************************************** 22 | * Everything underneath this line is managed by the CLI. 23 | **********************************************************************************************/ 24 | const barrels: string[] = [ 25 | // Angular specific barrels. 26 | '@angular/core', 27 | '@angular/common', 28 | '@angular/compiler', 29 | '@angular/forms', 30 | '@angular/http', 31 | '@angular/router', 32 | '@angular/platform-browser', 33 | '@angular/platform-browser-dynamic', 34 | 35 | // Thirdparty barrels. 36 | 'rxjs', 37 | 38 | // App specific barrels. 39 | 'app', 40 | 'app/shared', 41 | 'app/version', 42 | 'app/main-navigation', 43 | 'app/sandbox/guild-list', 44 | 'app/home', 45 | 'app/guilds-master', 46 | 'app/guilds-detail', 47 | 'app/sandbox/chapter-list', 48 | 'app/sandbox/chapter-member-list', 49 | 'app/chapters-master', 50 | 'app/members-master', 51 | 'app/sandbox/chapter-dynamic-form', 52 | 'app/sandbox/chapter-reactive-form', 53 | /** @cli-barrel */ 54 | ]; 55 | 56 | const cliSystemConfigPackages: any = {}; 57 | barrels.forEach((barrelName: string) => { 58 | cliSystemConfigPackages[barrelName] = { main: 'index' }; 59 | }); 60 | 61 | /** Type declaration for ambient System. */ 62 | declare var System: any; 63 | 64 | // Apply the CLI SystemJS configuration. 65 | System.config({ 66 | map: { 67 | '@angular': 'vendor/@angular', 68 | 'rxjs': 'vendor/rxjs', 69 | 'main': 'main.js' 70 | }, 71 | packages: cliSystemConfigPackages 72 | }); 73 | 74 | // Apply the user's configuration. 75 | System.config({ map, packages }); 76 | -------------------------------------------------------------------------------- /src/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "declaration": false, 5 | "emitDecoratorMetadata": true, 6 | "experimentalDecorators": true, 7 | "mapRoot": "/", 8 | "module": "commonjs", 9 | "moduleResolution": "node", 10 | "noEmitOnError": true, 11 | "noImplicitAny": false, 12 | "outDir": "../dist/", 13 | "rootDir": ".", 14 | "sourceMap": true, 15 | "target": "es5", 16 | "inlineSources": true 17 | }, 18 | 19 | "files": [ 20 | "main.ts", 21 | "typings.d.ts" 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /src/typings.d.ts: -------------------------------------------------------------------------------- 1 | // Typings reference file, see links for more information 2 | // https://github.com/typings/typings 3 | // https://www.typescriptlang.org/docs/handbook/writing-declaration-files.html 4 | 5 | /// 6 | declare var module: { id: string }; 7 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rulesDirectory": [ 3 | "node_modules/codelyzer" 4 | ], 5 | "rules": { 6 | "class-name": true, 7 | "comment-format": [ 8 | true, 9 | "check-space" 10 | ], 11 | "curly": true, 12 | "eofline": true, 13 | "forin": true, 14 | "indent": [ 15 | true, 16 | "spaces" 17 | ], 18 | "label-position": true, 19 | "label-undefined": true, 20 | "max-line-length": [ 21 | true, 22 | 140 23 | ], 24 | "member-access": false, 25 | "member-ordering": [ 26 | true, 27 | "static-before-instance", 28 | "variables-before-functions" 29 | ], 30 | "no-arg": true, 31 | "no-bitwise": true, 32 | "no-console": [ 33 | true, 34 | "debug", 35 | "info", 36 | "time", 37 | "timeEnd", 38 | "trace" 39 | ], 40 | "no-construct": true, 41 | "no-debugger": true, 42 | "no-duplicate-key": true, 43 | "no-duplicate-variable": true, 44 | "no-empty": false, 45 | "no-eval": true, 46 | "no-inferrable-types": true, 47 | "no-shadowed-variable": true, 48 | "no-string-literal": false, 49 | "no-switch-case-fall-through": true, 50 | "no-trailing-whitespace": true, 51 | "no-unused-expression": true, 52 | "no-unused-variable": true, 53 | "no-unreachable": true, 54 | "no-use-before-declare": true, 55 | "no-var-keyword": true, 56 | "object-literal-sort-keys": false, 57 | "one-line": [ 58 | true, 59 | "check-open-brace", 60 | "check-catch", 61 | "check-else", 62 | "check-whitespace" 63 | ], 64 | "quotemark": [ 65 | true, 66 | "single" 67 | ], 68 | "radix": true, 69 | "semicolon": [ 70 | "always" 71 | ], 72 | "triple-equals": [ 73 | true, 74 | "allow-null-check" 75 | ], 76 | "typedef-whitespace": [ 77 | true, 78 | { 79 | "call-signature": "nospace", 80 | "index-signature": "nospace", 81 | "parameter": "nospace", 82 | "property-declaration": "nospace", 83 | "variable-declaration": "nospace" 84 | } 85 | ], 86 | "variable-name": false, 87 | "whitespace": [ 88 | true, 89 | "check-branch", 90 | "check-decl", 91 | "check-operator", 92 | "check-separator", 93 | "check-type" 94 | ], 95 | 96 | "directive-selector-name": [true, "camelCase"], 97 | "component-selector-name": [true, "kebab-case"], 98 | "directive-selector-type": [true, "attribute"], 99 | "component-selector-type": [true, "element"], 100 | "use-input-property-decorator": true, 101 | "use-output-property-decorator": true, 102 | "use-host-property-decorator": true, 103 | "no-input-rename": true, 104 | "no-output-rename": true, 105 | "use-life-cycle-interface": true, 106 | "use-pipe-transform-interface": true, 107 | "component-class-suffix": true, 108 | "directive-class-suffix": true 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /typings.json: -------------------------------------------------------------------------------- 1 | { 2 | "globalDevDependencies": { 3 | "angular-protractor": "registry:dt/angular-protractor#1.5.0+20160425143459", 4 | "jasmine": "registry:dt/jasmine#2.2.0+20160621224255", 5 | "selenium-webdriver": "registry:dt/selenium-webdriver#2.44.0+20160317120654" 6 | }, 7 | "globalDependencies": { 8 | "es6-shim": "registry:dt/es6-shim#0.31.2+20160602141504" 9 | } 10 | } 11 | --------------------------------------------------------------------------------