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

utilities.mddocs/

0

# Utilities

1

2

Utility functions and helpers for form manipulation, data binding, reactive programming, and field configuration management.

3

4

## Capabilities

5

6

### Property Management

7

8

Utility functions for managing field properties and hidden properties.

9

10

```typescript { .api }

11

/**

12

* Define a hidden (non-enumerable) property on an object

13

* @param field - The object to define the property on

14

* @param prop - The property name

15

* @param defaultValue - The default value for the property

16

*/

17

function defineHiddenProp(field: any, prop: string, defaultValue: any): void;

18

19

/**

20

* Check if a field has a valid key for model binding

21

* @param field - The field configuration to check

22

* @returns True if field has a key

23

*/

24

function hasKey(field: FormlyFieldConfig): boolean;

25

```

26

27

**Usage Example:**

28

29

```typescript

30

import { defineHiddenProp, hasKey } from '@ngx-formly/core';

31

32

// Define a hidden property for internal use

33

const field: FormlyFieldConfig = { key: 'username', type: 'input' };

34

defineHiddenProp(field, '_internalId', 'field_123');

35

36

// Check if field can be bound to model

37

if (hasKey(field)) {

38

console.log('Field will be bound to model property:', field.key);

39

}

40

```

41

42

### Data Manipulation

43

44

Functions for cloning, merging, and retrieving field values.

45

46

```typescript { .api }

47

/**

48

* Deep clone a value, handling circular references and complex objects

49

* @param value - The value to clone

50

* @returns Deep cloned copy of the value

51

*/

52

function clone(value: any): any;

53

54

/**

55

* Reverse deep merge multiple objects, with later arguments taking precedence

56

* @param dest - The destination object

57

* @param args - Source objects to merge (later objects override earlier ones)

58

* @returns The merged object

59

*/

60

function reverseDeepMerge(dest: any, ...args: any[]): any;

61

62

/**

63

* Get the current value of a field from its form control or model

64

* @param field - The field configuration

65

* @returns The current field value

66

*/

67

function getFieldValue(field: FormlyFieldConfig): any;

68

```

69

70

**Usage Example:**

71

72

```typescript

73

import { clone, reverseDeepMerge, getFieldValue } from '@ngx-formly/core';

74

75

// Clone a complex object

76

const originalData = { user: { name: 'John', settings: { theme: 'dark' } } };

77

const clonedData = clone(originalData);

78

79

// Merge configuration objects

80

const baseConfig = { type: 'input', props: { label: 'Name' } };

81

const customConfig = { props: { placeholder: 'Enter name', required: true } };

82

const merged = reverseDeepMerge({}, baseConfig, customConfig);

83

// Result: { type: 'input', props: { label: 'Name', placeholder: 'Enter name', required: true } }

84

85

// Get current field value

86

const field: FormlyFieldConfig = {

87

key: 'email',

88

formControl: new FormControl('user@example.com')

89

};

90

const currentValue = getFieldValue(field); // 'user@example.com'

91

```

92

93

### Reactive Programming

94

95

Observable utilities for handling field changes and reactive updates.

96

97

```typescript { .api }

98

/**

99

* Create an observable from a field expression or value

100

* @param field - The field configuration

101

* @param expression - The expression to observe (string, function, or observable)

102

* @param defaultValue - Default value if expression is undefined

103

* @returns Observable that emits when the expression changes

104

*/

105

function observe<T>(

106

field: FormlyFieldConfig,

107

expression: string | ((field: FormlyFieldConfig) => T) | Observable<T>,

108

defaultValue?: T

109

): Observable<T>;

110

```

111

112

**Usage Example:**

113

114

```typescript

115

import { observe } from '@ngx-formly/core';

116

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

117

118

// Observe field property changes

119

const field: FormlyFieldConfig = {

120

key: 'email',

121

type: 'input',

122

expressions: {

123

'props.disabled': 'model.isReadonly'

124

}

125

};

126

127

// Observe the disabled state

128

observe(field, 'props.disabled', false)

129

.pipe(

130

distinctUntilChanged(),

131

map(disabled => disabled ? 'Field is disabled' : 'Field is enabled')

132

)

133

.subscribe(status => console.log(status));

134

135

// Observe using a function

136

observe(field, (f) => f.formControl?.valid, false)

137

.subscribe(isValid => {

138

console.log('Field validity changed:', isValid);

139

});

140

```

141

142

### FormlyGroup Template Component

143

144

Utility component for grouping fields without additional wrapper markup.

145

146

```typescript { .api }

147

/**

148

* Internal component for rendering field groups without wrapper markup

149

* Used by the form rendering system for fieldGroup configurations

150

*/

151

@Component({

152

selector: 'formly-group',

153

template: `<formly-field *ngFor="let f of field.fieldGroup" [field]="f"></formly-field>`

154

})

155

export class FormlyGroup {

156

/** The field configuration containing fieldGroup */

157

@Input() field: FormlyFieldConfig;

158

}

159

```

160

161

**Usage Example:**

162

163

```typescript

164

// Field configuration using fieldGroup

165

const fieldConfig: FormlyFieldConfig = {

166

fieldGroup: [

167

{

168

key: 'firstName',

169

type: 'input',

170

props: { label: 'First Name', required: true }

171

},

172

{

173

key: 'lastName',

174

type: 'input',

175

props: { label: 'Last Name', required: true }

176

}

177

],

178

fieldGroupClassName: 'row' // CSS class for the group

179

};

180

```

181

182

## Types

183

184

### Utility Function Types

185

186

```typescript { .api }

187

/**

188

* Type for field expression that can be a string, function, or observable

189

*/

190

type FieldExpression<T = any> = string | ((field: FormlyFieldConfig) => T) | Observable<T>;

191

192

/**

193

* Map of field expressions for different properties

194

*/

195

interface FieldExpressions {

196

[property: string]: FieldExpression;

197

198

/** Expression for CSS class names */

199

className?: FieldExpression<string>;

200

201

/** Expression for hiding the field */

202

hide?: FieldExpression<boolean>;

203

204

/** Expression for disabling the field */

205

'props.disabled'?: FieldExpression<boolean>;

206

207

/** Expression for making the field required */

208

'props.required'?: FieldExpression<boolean>;

209

}

210

211

/**

212

* Interface for objects that can be cloned

213

*/

214

interface Cloneable {

215

clone?(): any;

216

}

217

218

/**

219

* Options for merge operations

220

*/

221

interface MergeOptions {

222

/** Whether to merge arrays by concatenating */

223

arrayMerge?: boolean;

224

225

/** Whether to clone values during merge */

226

clone?: boolean;

227

}

228

```

229

230

### Expression Evaluation Types

231

232

```typescript { .api }

233

/**

234

* Context object passed to expression evaluation

235

*/

236

interface ExpressionContext {

237

/** The current field configuration */

238

field: FormlyFieldConfig;

239

240

/** The form model data */

241

model: any;

242

243

/** The current form state */

244

formState: any;

245

246

/** The form options */

247

options: FormlyFormOptions;

248

}

249

250

/**

251

* Result of expression evaluation

252

*/

253

interface ExpressionResult<T = any> {

254

/** The evaluated value */

255

value: T;

256

257

/** Whether the value has changed since last evaluation */

258

changed: boolean;

259

}

260

```

261

262

## Internal APIs

263

264

### Internal Utility Functions

265

266

These functions are marked with the `ɵ` prefix and are intended for internal use by the library.

267

268

```typescript { .api }

269

/**

270

* Internal function for defining hidden properties

271

* @internal

272

*/

273

function ɵdefineHiddenProp(field: any, prop: string, defaultValue: any): void;

274

275

/**

276

* Internal function for reverse deep merge operations

277

* @internal

278

*/

279

function ɵreverseDeepMerge(dest: any, ...args: any[]): any;

280

281

/**

282

* Internal function for getting field values

283

* @internal

284

*/

285

function ɵgetFieldValue(field: FormlyFieldConfig): any;

286

287

/**

288

* Internal function for cloning values

289

* @internal

290

*/

291

function ɵclone(value: any): any;

292

293

/**

294

* Internal function for creating observables

295

* @internal

296

*/

297

function ɵobserve<T>(

298

field: FormlyFieldConfig,

299

expression: FieldExpression<T>,

300

defaultValue?: T

301

): Observable<T>;

302

303

/**

304

* Internal function for checking if field has a key

305

* @internal

306

*/

307

function ɵhasKey(field: FormlyFieldConfig): boolean;

308

```

309

310

## Advanced Usage Examples

311

312

### Custom Expression Evaluator

313

314

```typescript

315

import { observe, FormlyFieldConfig } from '@ngx-formly/core';

316

import { combineLatest } from 'rxjs';

317

import { map } from 'rxjs/operators';

318

319

class CustomExpressionEvaluator {

320

evaluateConditionalVisibility(field: FormlyFieldConfig): Observable<boolean> {

321

const modelObservable = observe(field, 'model', {});

322

const formStateObservable = observe(field, 'formState', {});

323

324

return combineLatest([modelObservable, formStateObservable]).pipe(

325

map(([model, formState]) => {

326

// Complex visibility logic

327

return model.showAdvanced && formState.userLevel === 'expert';

328

})

329

);

330

}

331

}

332

```

333

334

### Custom Field Configuration Merger

335

336

```typescript

337

import { reverseDeepMerge, clone } from '@ngx-formly/core';

338

339

class FieldConfigurationManager {

340

mergeConfigurations(

341

baseConfig: FormlyFieldConfig,

342

...overrides: Partial<FormlyFieldConfig>[]

343

): FormlyFieldConfig {

344

// Clone base configuration to avoid mutations

345

const clonedBase = clone(baseConfig);

346

347

// Merge all overrides

348

return reverseDeepMerge(clonedBase, ...overrides);

349

}

350

351

createVariant(

352

baseConfig: FormlyFieldConfig,

353

variant: 'readonly' | 'required' | 'hidden'

354

): FormlyFieldConfig {

355

const variants = {

356

readonly: { props: { readonly: true } },

357

required: { props: { required: true } },

358

hidden: { hide: true }

359

};

360

361

return this.mergeConfigurations(baseConfig, variants[variant]);

362

}

363

}

364

```