or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

collections.mdcustom-validators.mdindex.mdintegration.mdvalidation-state.mdvalidators.md

custom-validators.mddocs/

0

# Custom Validators and Parameters

1

2

System for creating custom validation functions with parameter metadata support, enabling reusable and configurable validation logic.

3

4

## Capabilities

5

6

### withParams Function

7

8

Higher-order function for adding parameter metadata to validators, enabling parameter inspection and enhanced error reporting.

9

10

```javascript { .api }

11

/**

12

* Adds parameter metadata to a validator function

13

* @param params - Object containing parameter metadata

14

* @param validator - Validator function to wrap

15

*/

16

function withParams(

17

params: object,

18

validator: (value: any, parentVm?: any) => boolean | Promise<boolean>

19

): (value: any, parentVm?: any) => boolean | Promise<boolean>;

20

21

/**

22

* Closure-based parameter addition for dynamic parameter scenarios

23

* @param closure - Function that receives addParams function and returns validator

24

*/

25

function withParams(

26

closure: (addParams: (params: object) => void) => (value: any, parentVm?: any) => boolean | Promise<boolean>

27

): (value: any, parentVm?: any) => boolean | Promise<boolean>;

28

```

29

30

## Creating Custom Validators

31

32

### Simple Custom Validators

33

34

Basic custom validators without parameters.

35

36

**Usage:**

37

38

```javascript

39

import { withParams } from 'vuelidate'

40

41

// Simple validator without parameters

42

const strongPassword = (value) => {

43

if (!value) return true // allow empty, combine with required if needed

44

45

const hasUpper = /[A-Z]/.test(value)

46

const hasLower = /[a-z]/.test(value)

47

const hasNumber = /\d/.test(value)

48

const hasSpecial = /[!@#$%^&*(),.?":{}|<>]/.test(value)

49

50

return hasUpper && hasLower && hasNumber && hasSpecial

51

}

52

53

// Usage in component

54

validations: {

55

password: {

56

required,

57

strongPassword

58

}

59

}

60

```

61

62

### Parameterized Custom Validators

63

64

Custom validators that accept configuration parameters.

65

66

**Usage:**

67

68

```javascript

69

import { withParams } from 'vuelidate'

70

71

// Validator factory with parameters

72

const customMinLength = (min) => withParams(

73

{ type: 'customMinLength', min },

74

(value) => {

75

return !value || value.length >= min

76

}

77

)

78

79

// Date range validator

80

const dateRange = (startDate, endDate) => withParams(

81

{ type: 'dateRange', startDate, endDate },

82

(value) => {

83

if (!value) return true

84

const date = new Date(value)

85

return date >= new Date(startDate) && date <= new Date(endDate)

86

}

87

)

88

89

// Usage in component

90

validations: {

91

username: {

92

customMinLength: customMinLength(3)

93

},

94

eventDate: {

95

dateRange: dateRange('2024-01-01', '2024-12-31')

96

}

97

}

98

```

99

100

### Contextual Validators

101

102

Validators that access component context and other properties.

103

104

**Usage:**

105

106

```javascript

107

import { withParams } from 'vuelidate'

108

109

// Validator that accesses other component data

110

const dependsOnOtherField = withParams(

111

{ type: 'dependsOnOtherField' },

112

function(value, parentVm) {

113

// Access other properties via parentVm or this

114

const otherValue = parentVm.otherField

115

return !value || value !== otherValue

116

}

117

)

118

119

// Age-based validation

120

const ageBasedValidation = withParams(

121

{ type: 'ageBasedValidation' },

122

function(value, parentVm) {

123

const age = parentVm.age

124

if (age < 18) {

125

return !value || value.length <= 10 // shorter value for minors

126

}

127

return !value || value.length <= 50 // longer value for adults

128

}

129

)

130

131

// Usage in component

132

validations: {

133

field1: { dependsOnOtherField },

134

comment: { ageBasedValidation }

135

}

136

```

137

138

### Async Custom Validators

139

140

Validators that perform asynchronous operations like API calls.

141

142

**Usage:**

143

144

```javascript

145

import { withParams } from 'vuelidate'

146

147

// Async username availability check

148

const uniqueUsername = withParams(

149

{ type: 'uniqueUsername' },

150

async (value) => {

151

if (!value) return true

152

153

try {

154

const response = await fetch(`/api/check-username?username=${value}`)

155

const data = await response.json()

156

return data.available

157

} catch (error) {

158

// Handle error - could return false or true depending on strategy

159

return false

160

}

161

}

162

)

163

164

// Async email verification

165

const verifyEmail = withParams(

166

{ type: 'verifyEmail' },

167

(value) => {

168

if (!value) return true

169

170

return new Promise((resolve) => {

171

// Simulate API call

172

setTimeout(() => {

173

const isValid = value.includes('@') && !value.includes('spam')

174

resolve(isValid)

175

}, 1000)

176

})

177

}

178

)

179

180

// Usage in component

181

validations: {

182

username: {

183

required,

184

uniqueUsername

185

},

186

email: {

187

required,

188

email,

189

verifyEmail

190

}

191

}

192

```

193

194

### Closure-based Parameter Addition

195

196

Advanced parameter management using the closure form of `withParams`.

197

198

**Usage:**

199

200

```javascript

201

import { withParams } from 'vuelidate'

202

203

// Complex validator with dynamic parameters

204

const complexValidator = withParams((addParams) => {

205

return function(value, parentVm) {

206

// Add different parameters based on conditions

207

if (!value) {

208

addParams({ type: 'complex', reason: 'empty' })

209

return true

210

}

211

212

if (value.length < 5) {

213

addParams({ type: 'complex', reason: 'tooShort', minLength: 5 })

214

return false

215

}

216

217

if (!/^[a-zA-Z]/.test(value)) {

218

addParams({ type: 'complex', reason: 'mustStartWithLetter' })

219

return false

220

}

221

222

addParams({ type: 'complex', reason: 'valid' })

223

return true

224

}

225

})

226

227

// Validator with conditional sub-validations

228

const conditionalValidator = withParams((addParams) => {

229

return function(value, parentVm) {

230

const userType = parentVm.userType

231

232

addParams({ type: 'conditional', userType })

233

234

if (userType === 'admin') {

235

addParams({ minLength: 10 })

236

return !value || value.length >= 10

237

} else {

238

addParams({ minLength: 5 })

239

return !value || value.length >= 5

240

}

241

}

242

})

243

```

244

245

## Parameter Access

246

247

### Accessing Validator Parameters

248

249

Parameters added via `withParams` are accessible through the validation state.

250

251

**Usage:**

252

253

```javascript

254

// In component template or methods

255

export default {

256

// ... component setup

257

computed: {

258

passwordErrors() {

259

const validation = this.$v.password

260

261

if (validation.$error) {

262

const errors = []

263

264

// Access parameters from custom validators

265

if (!validation.customMinLength) {

266

const params = validation.customMinLength.$params

267

errors.push(`Minimum length is ${params.min} characters`)

268

}

269

270

if (!validation.strongPassword) {

271

errors.push('Password must contain uppercase, lowercase, number, and special character')

272

}

273

274

return errors

275

}

276

277

return []

278

}

279

}

280

}

281

```

282

283

### Parameter Inspection

284

285

Using parameters for dynamic error messages and UI behavior.

286

287

**Usage:**

288

289

```javascript

290

// Generic error message generator

291

function generateErrorMessage(fieldName, validation) {

292

for (const ruleName in validation) {

293

if (ruleName.startsWith('$') || validation[ruleName]) continue

294

295

const rule = validation[ruleName]

296

const params = rule.$params

297

298

if (params) {

299

switch (params.type) {

300

case 'minLength':

301

return `${fieldName} must be at least ${params.min} characters`

302

case 'dateRange':

303

return `${fieldName} must be between ${params.startDate} and ${params.endDate}`

304

case 'uniqueUsername':

305

return `${fieldName} is already taken`

306

default:

307

return `${fieldName} is invalid`

308

}

309

}

310

}

311

312

return `${fieldName} is invalid`

313

}

314

315

// Usage in component

316

computed: {

317

usernameError() {

318

return this.$v.username.$error

319

? generateErrorMessage('Username', this.$v.username)

320

: null

321

}

322

}

323

```

324

325

## Helper Utilities

326

327

### Common Validator Patterns

328

329

Reusable patterns for building custom validators.

330

331

```javascript { .api }

332

/**

333

* Core required check utility (exported from validators/common)

334

*/

335

function req(value: any): boolean;

336

337

/**

338

* Type-agnostic length utility (exported from validators/common)

339

*/

340

function len(value: any): number;

341

342

/**

343

* Resolve referenced values from component (exported from validators/common)

344

*/

345

function ref(reference: string | Function, vm: any, parentVm: any): any;

346

347

/**

348

* Regex-based validator template (exported from validators/common)

349

*/

350

function regex(type: string, expr: RegExp): (value: any) => boolean;

351

```

352

353

**Usage:**

354

355

```javascript

356

import { withParams, helpers } from 'vuelidate'

357

358

const { req, len, ref, regex } = helpers

359

360

// Using helper utilities

361

const customRequired = withParams(

362

{ type: 'customRequired' },

363

(value) => req(value)

364

)

365

366

const customLength = (min, max) => withParams(

367

{ type: 'customLength', min, max },

368

(value) => {

369

const length = len(value)

370

return length >= min && length <= max

371

}

372

)

373

374

const phoneNumber = regex('phoneNumber', /^\+?[\d\s\-\(\)]+$/)

375

376

const dependentField = (otherField) => withParams(

377

{ type: 'dependentField', otherField },

378

function(value, parentVm) {

379

const otherValue = ref(otherField, this, parentVm)

380

return !value || value !== otherValue

381

}

382

)

383

```