or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

configuration.mdfield-components.mdfield-types.mdindex.mdjson-schema.mdselect.mdservices.mdtesting.mdutilities.mdvalidation.md

validation.mddocs/

0

# Validation

1

2

Validation system with custom validators, validation messages, and error handling components for comprehensive form validation.

3

4

## Capabilities

5

6

### FormlyValidationMessage

7

8

Component for displaying validation error messages with customizable message rendering.

9

10

```typescript { .api }

11

/**

12

* Component for displaying field validation messages

13

*/

14

@Component({

15

selector: 'formly-validation-message',

16

template: `<div class="error-message">{{ errorMessage }}</div>`

17

})

18

export class FormlyValidationMessage implements OnInit {

19

/** The field configuration containing validation state */

20

@Input() field: FormlyFieldConfig;

21

22

/** The current error message to display */

23

errorMessage: string;

24

}

25

```

26

27

**Usage Example:**

28

29

```typescript

30

@Component({

31

template: `

32

<div class="form-field">

33

<input [formControl]="formControl" [formlyAttributes]="field">

34

<formly-validation-message

35

*ngIf="showError"

36

[field]="field">

37

</formly-validation-message>

38

</div>

39

`

40

})

41

export class CustomFieldComponent extends FieldType {

42

get showError() {

43

return this.field.showError && this.formControl.invalid;

44

}

45

}

46

```

47

48

### FormlyAttributes

49

50

Directive for applying field attributes and handling focus, blur, and change events.

51

52

```typescript { .api }

53

/**

54

* Directive for applying field attributes and event handling

55

*/

56

@Directive({

57

selector: '[formlyAttributes]',

58

host: {

59

'(focus)': 'onFocus($event)',

60

'(blur)': 'onBlur($event)',

61

'(change)': 'onChange($event)',

62

}

63

})

64

export class FormlyAttributes implements OnInit, DoCheck {

65

/** The field configuration */

66

@Input('formlyAttributes') field: FormlyFieldConfig;

67

68

/** Focus event handler */

69

onFocus(event: Event): void;

70

71

/** Blur event handler */

72

onBlur(event: Event): void;

73

74

/** Change event handler */

75

onChange(event: Event): void;

76

}

77

```

78

79

**Usage Example:**

80

81

```typescript

82

@Component({

83

template: `

84

<input

85

[formControl]="formControl"

86

[formlyAttributes]="field"

87

[placeholder]="props.placeholder"

88

[disabled]="props.disabled">

89

`

90

})

91

export class InputFieldComponent extends FieldType {}

92

```

93

94

### Validation Configuration

95

96

Field-level validation configuration supporting both sync and async validators.

97

98

```typescript { .api }

99

/**

100

* Validation configuration for individual fields

101

*/

102

interface FormlyFieldConfigValidators {

103

[key: string]: FormlyValidatorConfig | ValidatorFn | AsyncValidatorFn;

104

}

105

106

interface FormlyValidatorConfig {

107

/** The validator function */

108

validation: ValidatorFn | AsyncValidatorFn;

109

110

/** Options passed to the validator */

111

options?: any;

112

113

/** Custom error message for this validator */

114

message?: string | ((error: any, field: FormlyFieldConfig) => string);

115

}

116

```

117

118

**Usage Example:**

119

120

```typescript

121

const fieldConfig: FormlyFieldConfig = {

122

key: 'email',

123

type: 'input',

124

props: {

125

label: 'Email Address',

126

required: true,

127

type: 'email'

128

},

129

validators: {

130

required: {

131

validation: Validators.required,

132

message: 'Email is required'

133

},

134

email: {

135

validation: Validators.email,

136

message: 'Please enter a valid email address'

137

},

138

custom: {

139

validation: (control: AbstractControl) => {

140

return control.value && control.value.includes('@company.com')

141

? null

142

: { customDomain: true };

143

},

144

message: 'Email must be from company domain'

145

}

146

}

147

};

148

```

149

150

### Built-in Template Validators

151

152

Template-based validation using the `formlyAttributes` directive.

153

154

```typescript { .api }

155

/**

156

* Built-in validation attributes that can be applied via props

157

*/

158

interface ValidationProps {

159

/** Field is required */

160

required?: boolean;

161

162

/** Minimum length for text inputs */

163

minLength?: number;

164

165

/** Maximum length for text inputs */

166

maxLength?: number;

167

168

/** Minimum value for numeric inputs */

169

min?: number;

170

171

/** Maximum value for numeric inputs */

172

max?: number;

173

174

/** Pattern for validation */

175

pattern?: string | RegExp;

176

177

/** Email validation */

178

email?: boolean;

179

}

180

```

181

182

**Usage Example:**

183

184

```typescript

185

const fields: FormlyFieldConfig[] = [

186

{

187

key: 'username',

188

type: 'input',

189

props: {

190

label: 'Username',

191

required: true,

192

minLength: 3,

193

maxLength: 20,

194

pattern: /^[a-zA-Z0-9_]+$/

195

}

196

},

197

{

198

key: 'age',

199

type: 'input',

200

props: {

201

label: 'Age',

202

type: 'number',

203

required: true,

204

min: 18,

205

max: 100

206

}

207

}

208

];

209

```

210

211

### Legacy Validation Components

212

213

Legacy versions of validation components for backward compatibility.

214

215

```typescript { .api }

216

/**

217

* Legacy version of FormlyValidationMessage for backward compatibility

218

* @deprecated Use FormlyValidationMessage instead

219

*/

220

@Component({ selector: 'formly-validation-message' })

221

export class LegacyFormlyValidationMessage extends FormlyValidationMessage {}

222

223

/**

224

* Legacy version of FormlyAttributes for backward compatibility

225

* @deprecated Use FormlyAttributes instead

226

*/

227

@Directive({ selector: '[formlyAttributes]' })

228

export class LegacyFormlyAttributes extends FormlyAttributes {}

229

```

230

231

## Types

232

233

### Validation Types

234

235

```typescript { .api }

236

interface ValidatorOption {

237

/** Unique name for the validator */

238

name: string;

239

240

/** Validator function (sync or async) */

241

validation: ValidatorFn | AsyncValidatorFn;

242

243

/** Additional options for the validator */

244

options?: { [id: string]: any };

245

}

246

247

interface ValidationMessageOption {

248

/** Validator name this message applies to */

249

name: string;

250

251

/** Message string or function returning message */

252

message: string | ((error: any, field: FormlyFieldConfig) => string);

253

}

254

255

interface FormlyFieldConfigValidators {

256

/** Custom validators for the field */

257

[key: string]: FormlyValidatorConfig | ValidatorFn | AsyncValidatorFn;

258

}

259

260

interface FormlyValidatorConfig {

261

/** The validator function */

262

validation: ValidatorFn | AsyncValidatorFn;

263

264

/** Options passed to the validator */

265

options?: any;

266

267

/** Custom error message for this validator */

268

message?: string | ((error: any, field: FormlyFieldConfig) => string);

269

}

270

```

271

272

### Error Handling Types

273

274

```typescript { .api }

275

interface FormlyValidatorError {

276

/** The validator name that failed */

277

validator: string;

278

279

/** Error details from the validator */

280

error: any;

281

282

/** The field that has the error */

283

field: FormlyFieldConfig;

284

285

/** Custom error message */

286

message?: string;

287

}

288

289

interface FormlyValidationErrors {

290

[validatorName: string]: any;

291

}

292

```

293

294

### Validation Expression Types

295

296

```typescript { .api }

297

type ValidatorExpression = string | ((field: FormlyFieldConfig) => boolean) | Observable<boolean>;

298

299

interface ValidatorExpressions {

300

[validatorName: string]: ValidatorExpression;

301

}

302

```

303

304

## Validation Examples

305

306

### Custom Async Validator

307

308

```typescript

309

import { AbstractControl, AsyncValidatorFn } from '@angular/forms';

310

import { Observable, of, timer } from 'rxjs';

311

import { map, switchMap } from 'rxjs/operators';

312

313

function uniqueUsernameValidator(): AsyncValidatorFn {

314

return (control: AbstractControl): Observable<any> => {

315

if (!control.value) {

316

return of(null);

317

}

318

319

return timer(300).pipe(

320

switchMap(() => {

321

// Simulate API call

322

const takenUsernames = ['admin', 'user', 'test'];

323

const isTaken = takenUsernames.includes(control.value.toLowerCase());

324

return of(isTaken ? { usernameTaken: true } : null);

325

})

326

);

327

};

328

}

329

330

// Usage in field configuration

331

const fieldConfig: FormlyFieldConfig = {

332

key: 'username',

333

type: 'input',

334

props: {

335

label: 'Username',

336

required: true

337

},

338

asyncValidators: {

339

uniqueUsername: {

340

validation: uniqueUsernameValidator(),

341

message: 'This username is already taken'

342

}

343

}

344

};

345

```

346

347

### Cross-Field Validation

348

349

```typescript

350

import { FormGroup } from '@angular/forms';

351

352

function passwordMatchValidator(control: AbstractControl) {

353

const formGroup = control.parent as FormGroup;

354

355

if (!formGroup) {

356

return null;

357

}

358

359

const password = formGroup.get('password')?.value;

360

const confirmPassword = control.value;

361

362

return password === confirmPassword ? null : { passwordMismatch: true };

363

}

364

365

const fields: FormlyFieldConfig[] = [

366

{

367

key: 'password',

368

type: 'input',

369

props: {

370

label: 'Password',

371

type: 'password',

372

required: true,

373

minLength: 8

374

}

375

},

376

{

377

key: 'confirmPassword',

378

type: 'input',

379

props: {

380

label: 'Confirm Password',

381

type: 'password',

382

required: true

383

},

384

validators: {

385

passwordMatch: {

386

validation: passwordMatchValidator,

387

message: 'Passwords must match'

388

}

389

}

390

}

391

];

392

```