---
title: Form Validation
product: Form Library
description: With built-in client-side validation, you can both make sure respondents fill out all mandatory form fields and check if the input is correctly formatted before it is submitted to the server. View a free demo example for JavaScript to learn more.
framework: Angular
source: https://surveyjs.io/form-library/examples/javascript-form-validation/angular
index: https://surveyjs.io/form-library/examples/overview.md
---

# Form Validation (Angular)

User input validation is used to ensure that respondents fill out all required form fields and the format of values is correct before they are submitted to the server. This example demonstrates how to configure built-in client-side form input validation.

SurveyJS Form Library supports multiple validator types. Most of them are configured in the [`validators`](https://surveyjs.io/form-library/documentation/question#validators) array. Add one or more objects to it and set their `type` property to one of the validator types listed in the table below. Refer to the Description column for information on other properties applicable to a specific validator type. All types also support the `text` property that allows you to override default validation messages.

| `type` | Description |
| ------ | ----------- |
| `"numeric"` | Throws an error if the answer is not a number or if an entered number is outside the range between [`minValue`](https://surveyjs.io/Documentation/Library?id=NumericValidator#minValue) and [`maxValue`](https://surveyjs.io/Documentation/Library?id=NumericValidator#maxValue). Alternatively, you can set the [`min`](https://surveyjs.io/form-library/documentation/questiontextmodel#min) and [`max`](https://surveyjs.io/form-library/documentation/questiontextmodel#max) properties in the question object to specify the range. |
| `"text"` | Throws an error if the length of entered text is outside the range between [`minLength`](https://surveyjs.io/Documentation/Library?id=TextValidator#minLength) and [`maxLength`](https://surveyjs.io/Documentation/Library?id=TextValidator#maxLength). |
| `"email"` | Throws an error if an entered value is not a valid e-mail address. |
| `"answercount"` | Throws an error if a user selects fewer choices than specified by [`minCount`](https://surveyjs.io/Documentation/Library?id=AnswerCountValidator#minCount) or more choices than specified by [`maxCount`](https://surveyjs.io/Documentation/Library?id=AnswerCountValidator#maxCount). Applies only to the question types that can have multiple values (for instance, [Checkbox](https://surveyjs.io/Documentation/Library?id=questioncheckboxmodel)). |
| `"regex"` | Throws an error if an entered value does not match a regular expression defined in the [`regex`](https://surveyjs.io/Documentation/Library?id=RegexValidator#regex) property.  
| `"expression"` | Throws an error when the [`expression`](https://surveyjs.io/Documentation/Library?id=ExpressionValidator#expression) evaluates to `false` (see [Expressions](/Documentation/Library?id=design-survey-conditional-logic#expressions)). |

SurveyJS Form Library also supports a Required validator. It throws an error if the answer is empty. Unlike other validator types, the Required validator cannot be configured in the `validators` array. To add the Required validator to a question, enable the question's [`isRequired`](https://surveyjs.io/form-library/documentation/question#isRequired) property. If you want to override the default validation message, set the [`requiredErrorText`](https://surveyjs.io/form-library/documentation/question#requiredErrorText) property. You can also specify the required state dynamically based on a condition. Use the [`requiredIf`](https://surveyjs.io/form-library/documentation/question#requiredIf) property to do this. Refer to the following help topic for more information: [Conditional Visibility](https://surveyjs.io/form-library/documentation/design-survey-conditional-logic#conditional-visibility).

This demo shows form validation examples where each question uses one of the validator types from the table above to validate user input. Question descriptions explain which values are considered valid. Enter _invalid_ values to ensure that data validation works. In addition, all questions have the Required validator. Leave one or more form fields empty and click Complete. You will see a validation error.

In this demo, validation is triggered immediately after you leave an input field because the Survey's [`checkErrorsMode`](https://surveyjs.io/form-library/documentation/surveymodel#checkErrorsMode) property is set to `"onValueChanged"`. If you do not set this property, validation activates before a user proceeds to the next page or completes the survey.

## Files

### `src/app/components/json.ts`

```ts
export const json = {
  "checkErrorsMode": "onValueChanged",
  "elements": [{
    "name": "numericvalidator",
    "type": "text",
    "inputType": "number",
    "title": "Numeric Validator",
    "description": "Enter a number within the range of 0 to 100",
    "isRequired": true,
    "validators": [{
      "type": "numeric",
      "text": "Value must be within the range of 0 to 100",
      "minValue": 0,
      "maxValue": 100
    }]
  }, {
    "name": "textlengthvalidator",
    "type": "comment",
    "title": "Text Length Validator",
    "description": "Enter text no shorter than 10 and no longer than 280 symbols",
    "isRequired": true,
    "validators": [{
      "type": "text",
      "minLength": 10,
      "maxLength": 280
    }]
  }, {
    "name": "emailvalidator",
    "type": "text",
    "inputType": "email",
    "title": "E-mail Validator",
    "description": "Enter an e-mail address",
    "isRequired": true,
    "validators": [
      { "type": "email" }
    ]
  }, {
    "name": "answercountvalidator",
    "type": "checkbox",
    "title": "Answer Count Validator",
    "description": "Select between two to four options",
    "isRequired": true,
    "choices": [
      "Option 1",
      "Option 2",
      "Option 3",
      "Option 4",
      "Option 5",
      "Option 6"
    ],
    "colCount": 2,
    "validators": [{
      "type": "answercount",
      "minCount": 2,
      "maxCount": 4
    }]
  },{
    "name": "regexvalidator",
    "type": "text",
    "title": "RegEx Validator",
    "description": "Enter a password that contains at least one upper-case, one lower-case letter, a digit, and a special character",
    "isRequired": true,
    "validators": [{
      "type": "regex",
      "regex": "(?=.*\\d)(?=.*[a-z])(?=.*[A-Z])(?!.*\\s)(?=.*[@$!%*?&])[\\da-zA-Z@$!%*?&]+",
      "text": "Your password must contain at least one upper-case, one lower-case letter, a digit, and a special character"
    }]
  }, {
    "name": "expressionvalidator",
    "type": "multipletext",
    "title": "Expression Validator",
    "description": "Specify a range of numbers",
    "isRequired": true,
    "items": [{
      "name": "minvalue",
      "title": "Minimum value",
      "isRequired": true,
      "inputType": "number",
      "validators": [
        { "type": "numeric" }
      ]
    }, {
      "name": "maxvalue",
      "title": "Maximum value",
      "isRequired": true,
      "inputType": "number",
      "validators": [
        { "type": "numeric" }
      ]
    }],
    "validators": [{
      "type": "expression",
      "expression": "{expressionvalidator.minvalue} < {expressionvalidator.maxvalue} or {expressionvalidator.minvalue} empty or {expressionvalidator.maxvalue} empty",
      "text": "The minimum value must not exceed the maximum value"
    }]
  }]
};
```

### `src/app/components/survey.component.css`

```css
/* You can add your custom CSS here. */
```

### `src/app/components/survey.component.html`

```html
<survey [model]="model" style="position: absolute; top: 0; left: 0; right: 0; bottom: 0; height:100%"></survey>
```

### `src/app/components/survey.component.ts`

```ts
import { Component, OnInit } from "@angular/core";
import { Model } from "survey-core";
import { json } from "./json";
import "./survey.component.css";
import "survey-core/survey-core.min.css";

@Component({
    // tslint:disable-next-line:component-selector
    selector: "component-survey",
    templateUrl: "./survey.component.html",
    styleUrls: ["./survey.component.css"]
})
export class SurveyComponent implements OnInit {
    model: Model;
    ngOnInit() {
        const survey = new Model(json);
        survey.onComplete.add((sender, options) => {
            console.log(JSON.stringify(sender.data, null, 3));
        });
        this.model = survey;
    }
}
```

### `src/app/components/theme.ts`

```ts
export const themeJson = {};
```

### `src/app/app.component.css`

```css

```

### `src/app/app.component.html`

```html
<component-survey></component-survey>
```

### `src/app/app.component.ts`

```ts
import { Component } from "@angular/core";

@Component({
    selector: "app-root",
    templateUrl: "./app.component.html",
    styleUrls: ["./app.component.css"]
})
export class AppComponent {
    title = "CodeSandbox";
}
```

### `src/app/app.module.ts`

```ts
import { BrowserModule } from "@angular/platform-browser";
import { NgModule } from "@angular/core";

import { AppComponent } from "./app.component";
import { SurveyModule } from "survey-angular-ui";
import { SurveyComponent } from "./components/survey.component";

@NgModule({
    declarations: [AppComponent, SurveyComponent],
    imports: [BrowserModule, SurveyModule],
    providers: [],
    bootstrap: [AppComponent]
})
export class AppModule { }
```

### `src/environments/environment.prod.ts`

```ts
export const environment = {
    production: true
};
```

### `src/environments/environment.ts`

```ts
// The file contents for the current environment will overwrite these during build.
// The build system defaults to the dev environment which uses `environment.ts`, but if you do
// `ng build --env=prod` then `environment.prod.ts` will be used instead.
// The list of which env maps to which file can be found in `.angular-cli.json`.

export const environment = {
    production: false
};
```

### `src/index.html`

```html
<app-root></app-root>
```

### `src/main.ts`

```ts
import { enableProdMode } from "@angular/core";
import { platformBrowserDynamic } from "@angular/platform-browser-dynamic";

import { AppModule } from "./app/app.module";
import { environment } from "./environments/environment";

if (environment.production) {
    enableProdMode();
}

platformBrowserDynamic()
    .bootstrapModule(AppModule)
    .catch(err => console.log(err));
```

### `src/polyfills.ts`

```ts
/**
 * This file includes polyfills needed by Angular and is loaded before the app.
 * You can add your own extra polyfills to this file.
 *
 * This file is divided into 2 sections:
 *   1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers.
 *   2. Application imports. Files imported after ZoneJS that should be loaded before your main
 *      file.
 *
 * The current setup is for so-called "evergreen" browsers; the last versions of browsers that
 * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera),
 * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile.
 *
 * Learn more in https://angular.io/docs/ts/latest/guide/browser-support.html
 */

/***************************************************************************************************
 * BROWSER POLYFILLS
 */

/** IE9, IE10 and IE11 requires all of the following polyfills. **/
// import 'core-js/es6/symbol';
// import 'core-js/es6/object';
// import 'core-js/es6/function';
// import 'core-js/es6/parse-int';
// import 'core-js/es6/parse-float';
// import 'core-js/es6/number';
// import 'core-js/es6/math';
// import 'core-js/es6/string';
// import 'core-js/es6/date';
// import 'core-js/es6/array';
// import 'core-js/es6/regexp';
// import 'core-js/es6/map';
// import 'core-js/es6/weak-map';
// import 'core-js/es6/set';

/** IE10 and IE11 requires the following for NgClass support on SVG elements */
// import 'classlist.js';  // Run `npm install classlist.js`.

/** IE10 and IE11 requires the following for the Reflect API. */
// import 'core-js/es6/reflect';

/** Evergreen browsers require these. **/
// Used for reflect-metadata in JIT. If you use AOT (and only Angular decorators), you can remove.
import "core-js/proposals/reflect-metadata";

/**
 * Required to support Web Animations `@angular/platform-browser/animations`.
 * Needed for: All but Chrome, Firefox and Opera. http://caniuse.com/#feat=web-animation
 **/
// import 'web-animations-js';  // Run `npm install web-animations-js`.

/***************************************************************************************************
 * Zone JS is required by default for Angular itself.
 */
import "zone.js/dist/zone"; // Included with Angular CLI.

/***************************************************************************************************
 * APPLICATION IMPORTS
 */
```

### `src/styles.css`

```css
/* You can add your custom CSS here. */
```

### `src/typings.d.ts`

```ts
/* SystemJS module definition */
declare var module: NodeModule;
interface NodeModule {
    id: string;
}
```

### `.angular-cli.json`

```json
{
  "apps": [
    {
      "root": "src",
      "outDir": "dist",
      "assets": [ "assets", "favicon.ico" ],
      "index": "index.html",
      "main": "main.ts",
      "polyfills": "polyfills.ts",
      "prefix": "app",
      "styles": [ "styles.css" ],
      "scripts": [ ],
      "environmentSource": "environments/environment.ts",
      "environments": {
        "dev": "environments/environment.ts",
        "prod": "environments/environment.prod.ts"
      }
    }
  ]
}
```

### `_tsconfig.json`

```json
{
  "compileOnSave": false,
  "compilerOptions": {
    "baseUrl": "./",
    "outDir": "./dist/out-tsc",
    "sourceMap": true,
    "declaration": false,
    "allowSyntheticDefaultImports": true,
    "downlevelIteration": true,
    "experimentalDecorators": true,
    "moduleResolution": "node",
    "importHelpers": true,
    "resolveJsonModule": true,
    "target": "es2015",
    "module": "es2020",
    "lib": [
      "es2018",
      "dom"
    ]
  }
}
```

### `package.json`

```json
{
  "name": "surveyjs-angular",
  "scripts": {
    "ng": "ng",
    "start": "ng serve",
    "build": "ng build --prod",
    "test": "ng test",
    "lint": "ng lint",
    "e2e": "ng e2e"
  },
  "private": true,
  "dependencies": {
    "@angular/animations": "14.1.1",
    "@angular/cdk": "14.1.1",
    "@angular/common": "14.1.1",
    "@angular/compiler": "14.1.1",
    "@angular/core": "14.1.1",
    "@angular/forms": "14.1.1",
    "@angular/platform-browser": "14.1.1",
    "@angular/platform-browser-dynamic": "14.1.1",
    "@angular/router": "14.1.1",
    "core-js": "3.6.4",
    "rxjs": "6.5.4",
    "survey-core": "latest",
    "survey-angular-ui": "latest",
    "tslib": "1.13.0",
    "zone.js": "0.11.7"
  },
  "devDependencies": {
    "@angular/cli": "1.6.6",
    "@angular/compiler-cli": "^5.2.0",
    "@angular/language-service": "^5.2.0",
    "@types/core-js": "0.9.46",
    "@types/jasmine": "~2.8.3",
    "@types/jasminewd2": "~2.0.2",
    "@types/node": "~6.0.60",
    "codelyzer": "^4.0.1",
    "jasmine-core": "~2.8.0",
    "jasmine-spec-reporter": "~4.2.1",
    "karma": "~2.0.0",
    "karma-chrome-launcher": "~2.2.0",
    "karma-coverage-istanbul-reporter": "^1.2.1",
    "karma-jasmine": "~1.1.0",
    "karma-jasmine-html-reporter": "^0.2.2",
    "protractor": "~5.1.2",
    "ts-node": "~4.1.0",
    "tslint": "~5.9.1",
    "typescript": "3.9.7"
  },
  "keywords": [ "angular", "surveyjs" ],
  "description": "SurveyJS-Angular example project"
}
```

## Other Frameworks

- [React](https://surveyjs.io/form-library/examples/javascript-form-validation/reactjs.md)
- [Vue 3](https://surveyjs.io/form-library/examples/javascript-form-validation/vue3js.md)
- [jQuery](https://surveyjs.io/form-library/examples/javascript-form-validation/jquery.md)
- [Vanilla JS](https://surveyjs.io/form-library/examples/javascript-form-validation/vanillajs.md)
