├── .angular-cli.json
├── .firebaserc
├── .gitignore
├── .travis.yml
├── README.md
├── firebase.json
├── package.json
├── src
├── app
│ ├── app-routing.module.ts
│ ├── app.component.html
│ ├── app.component.ts
│ ├── app.module.ts
│ ├── field-error-display
│ │ ├── field-error-display.component.css
│ │ ├── field-error-display.component.html
│ │ └── field-error-display.component.ts
│ ├── simple-form
│ │ ├── simple-form.component.html
│ │ └── simple-form.component.ts
│ ├── submit-flag-form
│ │ ├── submit-flag-form.component.html
│ │ └── submit-flag-form.component.ts
│ └── validate-fields-submit-form
│ │ ├── validate-fields-submit-form.component.html
│ │ └── validate-fields-submit-form.component.ts
├── assets
│ └── .gitkeep
├── environments
│ ├── environment.prod.ts
│ └── environment.ts
├── index.html
├── main.ts
├── polyfills.ts
├── styles.css
├── tsconfig.app.json
└── typings.d.ts
└── tsconfig.json
/.angular-cli.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
3 | "project": {
4 | "name": "angular-reactive-forms-valitate-submit"
5 | },
6 | "apps": [
7 | {
8 | "root": "src",
9 | "outDir": "dist",
10 | "assets": [
11 | "assets",
12 | "favicon.ico"
13 | ],
14 | "index": "index.html",
15 | "main": "main.ts",
16 | "polyfills": "polyfills.ts",
17 | "test": "test.ts",
18 | "tsconfig": "tsconfig.app.json",
19 | "testTsconfig": "tsconfig.spec.json",
20 | "prefix": "app",
21 | "styles": [
22 | "../node_modules/bootstrap/dist/css/bootstrap.min.css",
23 | "styles.css"
24 | ],
25 | "scripts": [],
26 | "environmentSource": "environments/environment.ts",
27 | "environments": {
28 | "dev": "environments/environment.ts",
29 | "prod": "environments/environment.prod.ts"
30 | }
31 | }
32 | ],
33 | "e2e": {
34 | "protractor": {
35 | "config": "./protractor.conf.js"
36 | }
37 | },
38 | "lint": [
39 | {
40 | "project": "src/tsconfig.app.json",
41 | "exclude": "**/node_modules/**"
42 | },
43 | {
44 | "project": "src/tsconfig.spec.json",
45 | "exclude": "**/node_modules/**"
46 | },
47 | {
48 | "project": "e2e/tsconfig.e2e.json",
49 | "exclude": "**/node_modules/**"
50 | }
51 | ],
52 | "test": {
53 | "karma": {
54 | "config": "./karma.conf.js"
55 | }
56 | },
57 | "defaults": {
58 | "styleExt": "css",
59 | "component": {
60 | "spec": false,
61 | "inlineStyle": true,
62 | "inlineTemplate": false
63 | },
64 | "directive": {
65 | "spec": false
66 | },
67 | "class": {
68 | "spec": false
69 | },
70 | "guard": {
71 | "spec": false
72 | },
73 | "module": {
74 | "spec": false
75 | },
76 | "pipe": {
77 | "spec": false
78 | },
79 | "service": {
80 | "spec": false
81 | }
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/.firebaserc:
--------------------------------------------------------------------------------
1 | {
2 | "projects": {
3 | "default": "ng-forms-fields-validation"
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See http://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # compiled output
4 | /dist
5 | /tmp
6 | /out-tsc
7 |
8 | # dependencies
9 | /node_modules
10 |
11 | # IDEs and editors
12 | /.idea
13 | .project
14 | .classpath
15 | .c9/
16 | *.launch
17 | .settings/
18 | *.sublime-workspace
19 |
20 | # IDE - VSCode
21 | .vscode/*
22 | !.vscode/settings.json
23 | !.vscode/tasks.json
24 | !.vscode/launch.json
25 | !.vscode/extensions.json
26 |
27 | # misc
28 | /.sass-cache
29 | /connect.lock
30 | /coverage
31 | /libpeerconnection.log
32 | npm-debug.log
33 | testem.log
34 | /typings
35 |
36 | # e2e
37 | /e2e/*.js
38 | /e2e/*.map
39 |
40 | # System Files
41 | .DS_Store
42 | Thumbs.db
43 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 |
3 | node_js:
4 | - node # latest node
5 |
6 | before_script:
7 | - npm install -g --silent firebase-tools
8 | - npm install -g --silent @angular/cli
9 |
10 | script:
11 | - ng build --prod
12 |
13 | after_success:
14 | - test $TRAVIS_BRANCH = "master" && test $TRAVIS_PULL_REQUEST = "false" && firebase deploy --token $FIREBASE_TOKEN --non-interactive
15 |
16 | notifications:
17 | email:
18 | on_failure: change
19 | on_success: change
20 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | [](https://greenkeeper.io/)
3 |
4 | [](https://travis-ci.org/loiane/angular-reactive-forms-validate-submit)
5 |
6 | Live demo: https://ng-forms-fields-validation.firebaseapp.com
7 |
8 | # angular-reactive-forms-validate-submit
9 |
10 | This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 1.2.6.
11 |
12 | ## Development server
13 |
14 | Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files.
15 |
16 | ## Code scaffolding
17 |
18 | Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|module`.
19 |
20 | ## Build
21 |
22 | Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `-prod` flag for a production build.
23 |
24 | ## Running unit tests
25 |
26 | Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).
27 |
28 | ## Running end-to-end tests
29 |
30 | Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/).
31 | Before running the tests make sure you are serving the app via `ng serve`.
32 |
33 | ## Further help
34 |
35 | To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md).
--------------------------------------------------------------------------------
/firebase.json:
--------------------------------------------------------------------------------
1 | {
2 | "hosting": {
3 | "public": "dist",
4 | "rewrites": [
5 | {
6 | "source": "**",
7 | "destination": "/index.html"
8 | }
9 | ]
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "angular-reactive-forms-validate-submit",
3 | "version": "0.0.0",
4 | "license": "MIT",
5 | "scripts": {
6 | "ng": "ng",
7 | "start": "ng serve",
8 | "build": "ng build",
9 | "test": "echo \"Error: no test... minimal project\" && exit 1",
10 | "lint": "echo \"Error: no lint... minimal project\" && exit 1",
11 | "e2e": "echo \"Error: no e2e... minimal project\" && exit 1"
12 | },
13 | "private": true,
14 | "dependencies": {
15 | "@angular/animations": "^5.0.2",
16 | "@angular/common": "^5.0.2",
17 | "@angular/compiler": "^5.0.2",
18 | "@angular/core": "^5.0.2",
19 | "@angular/forms": "^5.0.2",
20 | "@angular/http": "^5.0.0",
21 | "@angular/platform-browser": "^5.0.2",
22 | "@angular/platform-browser-dynamic": "^5.0.2",
23 | "@angular/router": "^5.0.2",
24 | "bootstrap": "^3.3.7",
25 | "core-js": "^2.4.1",
26 | "rxjs": "^5.4.1",
27 | "zone.js": "^0.8.14"
28 | },
29 | "devDependencies": {
30 | "@angular/cli": "1.5.1",
31 | "@angular/compiler-cli": "^5.0.2",
32 | "@angular/language-service": "^5.0.0",
33 | "typescript": "~2.6.1"
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/app/app-routing.module.ts:
--------------------------------------------------------------------------------
1 | import { SubmitFlagFormComponent } from './submit-flag-form/submit-flag-form.component';
2 | import { ValidateFieldsSubmitFormComponent } from './validate-fields-submit-form/validate-fields-submit-form.component';
3 | import { SimpleFormComponent } from './simple-form/simple-form.component';
4 | import { NgModule } from '@angular/core';
5 | import { Routes, RouterModule } from '@angular/router';
6 |
7 | const routes: Routes = [
8 | {
9 | path: '',
10 | children: [
11 | { path: 'simpleForm', component: SimpleFormComponent },
12 | { path: 'validateSubmit', component: ValidateFieldsSubmitFormComponent },
13 | { path: 'submitFlag', component: SubmitFlagFormComponent }
14 | ]
15 | }
16 | ];
17 |
18 | @NgModule({
19 | imports: [RouterModule.forRoot(routes)],
20 | exports: [RouterModule]
21 | })
22 | export class AppRoutingModule { }
23 |
--------------------------------------------------------------------------------
/src/app/app.component.html:
--------------------------------------------------------------------------------
1 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/src/app/app.component.ts:
--------------------------------------------------------------------------------
1 | import { Component } from '@angular/core';
2 |
3 | @Component({
4 | selector: 'app-root',
5 | templateUrl: './app.component.html',
6 | styles: []
7 | })
8 | export class AppComponent {}
9 |
--------------------------------------------------------------------------------
/src/app/app.module.ts:
--------------------------------------------------------------------------------
1 | import { BrowserModule } from '@angular/platform-browser';
2 | import { NgModule } from '@angular/core';
3 | import { ReactiveFormsModule } from '@angular/forms';
4 |
5 | import { AppRoutingModule } from './app-routing.module';
6 | import { AppComponent } from './app.component';
7 | import { SimpleFormComponent } from './simple-form/simple-form.component';
8 | import { SubmitFlagFormComponent } from './submit-flag-form/submit-flag-form.component';
9 | import { ValidateFieldsSubmitFormComponent } from './validate-fields-submit-form/validate-fields-submit-form.component';
10 | import { FieldErrorDisplayComponent } from './field-error-display/field-error-display.component';
11 |
12 | @NgModule({
13 | declarations: [
14 | AppComponent,
15 | SimpleFormComponent,
16 | SubmitFlagFormComponent,
17 | ValidateFieldsSubmitFormComponent,
18 | FieldErrorDisplayComponent
19 | ],
20 | imports: [
21 | BrowserModule,
22 | AppRoutingModule,
23 | ReactiveFormsModule
24 | ],
25 | providers: [],
26 | bootstrap: [AppComponent]
27 | })
28 | export class AppModule { }
29 |
--------------------------------------------------------------------------------
/src/app/field-error-display/field-error-display.component.css:
--------------------------------------------------------------------------------
1 | .error-msg {
2 | color: #a94442;
3 | }
4 | .fix-error-icon {
5 | top: 27px;
6 | }
--------------------------------------------------------------------------------
/src/app/field-error-display/field-error-display.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
(error)
4 |
5 | {{ errorMsg }}
6 |
7 |
--------------------------------------------------------------------------------
/src/app/field-error-display/field-error-display.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit, Input } from '@angular/core';
2 |
3 | @Component({
4 | selector: 'app-field-error-display',
5 | templateUrl: './field-error-display.component.html',
6 | styleUrls: ['./field-error-display.component.css']
7 | })
8 | export class FieldErrorDisplayComponent {
9 |
10 | @Input() errorMsg: string;
11 | @Input() displayError: boolean;
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/src/app/simple-form/simple-form.component.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/app/simple-form/simple-form.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit } from '@angular/core';
2 | import { FormGroup, FormBuilder, Validators } from '@angular/forms';
3 |
4 | @Component({
5 | selector: 'app-simple-form',
6 | templateUrl: './simple-form.component.html',
7 | styles: []
8 | })
9 | export class SimpleFormComponent implements OnInit {
10 |
11 | form: FormGroup;
12 |
13 | constructor(private formBuilder: FormBuilder) { }
14 |
15 | ngOnInit() {
16 | this.form = this.formBuilder.group({
17 | email: [null, [Validators.required, Validators.email]],
18 | password: [null, Validators.required],
19 | });
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/app/submit-flag-form/submit-flag-form.component.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/app/submit-flag-form/submit-flag-form.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit } from '@angular/core';
2 | import { FormGroup, FormBuilder, Validators } from '@angular/forms';
3 |
4 | @Component({
5 | selector: 'app-submit-flag-form',
6 | templateUrl: './submit-flag-form.component.html',
7 | styles: []
8 | })
9 | export class SubmitFlagFormComponent implements OnInit {
10 | form: FormGroup;
11 | private formSumitAttempt: boolean;
12 |
13 | constructor(private formBuilder: FormBuilder) {}
14 |
15 | ngOnInit() {
16 | this.form = this.formBuilder.group({
17 | name: [null, Validators.required],
18 | email: [null, [Validators.required, Validators.email]],
19 | address: this.formBuilder.group({
20 | street: [null, Validators.required],
21 | street2: [null],
22 | zipCode: [null, Validators.required],
23 | city: [null, Validators.required],
24 | state: [null, Validators.required],
25 | country: [null, Validators.required]
26 | })
27 | });
28 | }
29 |
30 | isFieldValid(field: string) {
31 | return (
32 | (!this.form.get(field).valid && this.form.get(field).touched) ||
33 | (this.form.get(field).untouched && this.formSumitAttempt)
34 | );
35 | }
36 |
37 | displayFieldCss(field: string) {
38 | return {
39 | 'has-error': this.isFieldValid(field),
40 | 'has-feedback': this.isFieldValid(field)
41 | };
42 | }
43 |
44 | onSubmit() {
45 | this.formSumitAttempt = true;
46 | if (this.form.valid) {
47 | console.log('form submitted');
48 | }
49 | }
50 |
51 | reset() {
52 | this.form.reset();
53 | this.formSumitAttempt = false;
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/app/validate-fields-submit-form/validate-fields-submit-form.component.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/app/validate-fields-submit-form/validate-fields-submit-form.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit } from '@angular/core';
2 | import {
3 | FormGroup,
4 | FormBuilder,
5 | Validators,
6 | FormControl
7 | } from '@angular/forms';
8 |
9 | @Component({
10 | selector: 'app-validate-fields-submit-form',
11 | templateUrl: './validate-fields-submit-form.component.html',
12 | styles: []
13 | })
14 | export class ValidateFieldsSubmitFormComponent implements OnInit {
15 | form: FormGroup;
16 |
17 | constructor(private formBuilder: FormBuilder) {}
18 |
19 | ngOnInit() {
20 | this.form = this.formBuilder.group({
21 | name: [null, Validators.required],
22 | email: [null, [Validators.required, Validators.email]],
23 | address: this.formBuilder.group({
24 | street: [null, Validators.required],
25 | street2: [null],
26 | zipCode: [null, Validators.required],
27 | city: [null, Validators.required],
28 | state: [null, Validators.required],
29 | country: [null, Validators.required]
30 | })
31 | });
32 | }
33 |
34 | isFieldValid(field: string) {
35 | return !this.form.get(field).valid && this.form.get(field).touched;
36 | }
37 |
38 | displayFieldCss(field: string) {
39 | return {
40 | 'has-error': this.isFieldValid(field),
41 | 'has-feedback': this.isFieldValid(field)
42 | };
43 | }
44 |
45 | onSubmit() {
46 | console.log(this.form);
47 | if (this.form.valid) {
48 | console.log('form submitted');
49 | } else {
50 | this.validateAllFormFields(this.form);
51 | }
52 | }
53 |
54 | validateAllFormFields(formGroup: FormGroup) {
55 | Object.keys(formGroup.controls).forEach(field => {
56 | console.log(field);
57 | const control = formGroup.get(field);
58 | if (control instanceof FormControl) {
59 | control.markAsTouched({ onlySelf: true });
60 | } else if (control instanceof FormGroup) {
61 | this.validateAllFormFields(control);
62 | }
63 | });
64 | }
65 |
66 | reset(){
67 | this.form.reset();
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/src/assets/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/loiane/angular-reactive-forms-validate-submit/97a7e9ebd834b0913c15a0fc27fe19b2ffe9a05d/src/assets/.gitkeep
--------------------------------------------------------------------------------
/src/environments/environment.prod.ts:
--------------------------------------------------------------------------------
1 | export const environment = {
2 | production: true
3 | };
4 |
--------------------------------------------------------------------------------
/src/environments/environment.ts:
--------------------------------------------------------------------------------
1 | // The file contents for the current environment will overwrite these during build.
2 | // The build system defaults to the dev environment which uses `environment.ts`, but if you do
3 | // `ng build --env=prod` then `environment.prod.ts` will be used instead.
4 | // The list of which env maps to which file can be found in `.angular-cli.json`.
5 |
6 | export const environment = {
7 | production: false
8 | };
9 |
--------------------------------------------------------------------------------
/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | AngularReactiveFormsValitateSubmit
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/src/main.ts:
--------------------------------------------------------------------------------
1 | import { enableProdMode } from '@angular/core';
2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
3 |
4 | import { AppModule } from './app/app.module';
5 | import { environment } from './environments/environment';
6 |
7 | if (environment.production) {
8 | enableProdMode();
9 | }
10 |
11 | platformBrowserDynamic().bootstrapModule(AppModule);
12 |
--------------------------------------------------------------------------------
/src/polyfills.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * This file includes polyfills needed by Angular and is loaded before the app.
3 | * You can add your own extra polyfills to this file.
4 | *
5 | * This file is divided into 2 sections:
6 | * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers.
7 | * 2. Application imports. Files imported after ZoneJS that should be loaded before your main
8 | * file.
9 | *
10 | * The current setup is for so-called "evergreen" browsers; the last versions of browsers that
11 | * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera),
12 | * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile.
13 | *
14 | * Learn more in https://angular.io/docs/ts/latest/guide/browser-support.html
15 | */
16 |
17 | /***************************************************************************************************
18 | * BROWSER POLYFILLS
19 | */
20 |
21 | /** IE9, IE10 and IE11 requires all of the following polyfills. **/
22 | // import 'core-js/es6/symbol';
23 | // import 'core-js/es6/object';
24 | // import 'core-js/es6/function';
25 | // import 'core-js/es6/parse-int';
26 | // import 'core-js/es6/parse-float';
27 | // import 'core-js/es6/number';
28 | // import 'core-js/es6/math';
29 | // import 'core-js/es6/string';
30 | // import 'core-js/es6/date';
31 | // import 'core-js/es6/array';
32 | // import 'core-js/es6/regexp';
33 | // import 'core-js/es6/map';
34 | // import 'core-js/es6/weak-map';
35 | // import 'core-js/es6/set';
36 |
37 | /** IE10 and IE11 requires the following for NgClass support on SVG elements */
38 | // import 'classlist.js'; // Run `npm install --save classlist.js`.
39 |
40 | /** Evergreen browsers require these. **/
41 | import 'core-js/es6/reflect';
42 | import 'core-js/es7/reflect';
43 |
44 |
45 | /**
46 | * Required to support Web Animations `@angular/animation`.
47 | * Needed for: All but Chrome, Firefox and Opera. http://caniuse.com/#feat=web-animation
48 | **/
49 | // import 'web-animations-js'; // Run `npm install --save web-animations-js`.
50 |
51 |
52 |
53 | /***************************************************************************************************
54 | * Zone JS is required by Angular itself.
55 | */
56 | import 'zone.js/dist/zone'; // Included with Angular CLI.
57 |
58 |
59 |
60 | /***************************************************************************************************
61 | * APPLICATION IMPORTS
62 | */
63 |
64 | /**
65 | * Date, currency, decimal and percent pipes.
66 | * Needed for: All but Chrome, Firefox, Edge, IE11 and Safari 10
67 | */
68 | // import 'intl'; // Run `npm install --save intl`.
69 | /**
70 | * Need to import at least one locale-data with intl.
71 | */
72 | // import 'intl/locale-data/jsonp/en';
73 |
--------------------------------------------------------------------------------
/src/styles.css:
--------------------------------------------------------------------------------
1 | /* You can add global styles to this file, and also import other style files */
2 | .control-label.required:after {
3 | color: #d00;
4 | content: "*";
5 | position: absolute;
6 | margin-left: 5px;
7 | top:7px;
8 | }
--------------------------------------------------------------------------------
/src/tsconfig.app.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "../out-tsc/app",
5 | "baseUrl": "./",
6 | "module": "es2015",
7 | "types": []
8 | },
9 | "exclude": [
10 | "test.ts",
11 | "**/*.spec.ts"
12 | ]
13 | }
14 |
--------------------------------------------------------------------------------
/src/typings.d.ts:
--------------------------------------------------------------------------------
1 | /* SystemJS module definition */
2 | declare var module: NodeModule;
3 | interface NodeModule {
4 | id: string;
5 | }
6 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compileOnSave": false,
3 | "compilerOptions": {
4 | "outDir": "./dist/out-tsc",
5 | "sourceMap": true,
6 | "declaration": false,
7 | "moduleResolution": "node",
8 | "emitDecoratorMetadata": true,
9 | "experimentalDecorators": true,
10 | "target": "es5",
11 | "typeRoots": [
12 | "node_modules/@types"
13 | ],
14 | "lib": [
15 | "es2016",
16 | "dom"
17 | ]
18 | }
19 | }
20 |
--------------------------------------------------------------------------------