Skip to content

Commit e3ca99e

Browse files
committed
chore: fix usage of field.api for consistency, wrote tests
1 parent 3128389 commit e3ca99e

File tree

7 files changed

+102
-15
lines changed

7 files changed

+102
-15
lines changed

examples/angular/large-form/src/app/app.component.ts

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { Component, input } from '@angular/core'
22
import {
3+
TanStackAppField,
34
TanStackField,
4-
TanStackFieldComponent,
55
injectField,
66
injectForm,
77
injectStore,
@@ -15,25 +15,35 @@ import type {
1515
selector: 'app-text-field',
1616
standalone: true,
1717
template: `
18-
<label [for]="lastName.api().name">{{ label() }}</label>
18+
<label [for]="field.api.name">{{ label() }}</label>
1919
<input
20-
[id]="lastName.api().name"
21-
[name]="lastName.api().name"
22-
[value]="lastName.api().state.value"
23-
(blur)="lastName.api().handleBlur()"
24-
(input)="lastName.api().handleChange($any($event).target.value)"
20+
[id]="field.api.name"
21+
[name]="field.api.name"
22+
[value]="field.api.state.value"
23+
(blur)="field.api.handleBlur()"
24+
(input)="field.api.handleChange($any($event).target.value)"
2525
/>
26+
@if (field.api.state.meta.isTouched) {
27+
@for (error of field.api.state.meta.errors; track $index) {
28+
<div style="color: red">
29+
{{ error }}
30+
</div>
31+
}
32+
}
33+
@if (field.api.state.meta.isValidating) {
34+
<p>Validating...</p>
35+
}
2636
`,
2737
})
2838
export class AppTextField {
2939
label = input.required<string>()
30-
lastName = injectField<string>()
40+
field = injectField<string>()
3141
}
3242

3343
@Component({
3444
selector: 'app-root',
3545
standalone: true,
36-
imports: [TanStackField, TanStackFieldComponent, AppTextField],
46+
imports: [TanStackField, TanStackAppField, AppTextField],
3747
template: `
3848
<form (submit)="handleSubmit($event)">
3949
<div>

packages/angular-form/src/app-field.component.ts renamed to packages/angular-form/src/app-field.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import {
55
FieldAsyncValidateOrFn,
66
FieldValidateOrFn,
77
} from '@tanstack/form-core'
8-
import { TanStackField } from './tanstack-field.directive'
8+
import { TanStackField } from './tanstack-field'
99
import { TanStackFieldInjectable } from './injectable'
1010
import type {
1111
FormAsyncValidateOrFn,
@@ -17,7 +17,7 @@ import type {
1717
standalone: true,
1818
providers: [TanStackFieldInjectable],
1919
})
20-
export class TanStackFieldComponent<
20+
export class TanStackAppField<
2121
TParentData,
2222
const TName extends DeepKeys<TParentData>,
2323
TData extends DeepValue<TParentData, TName>,
@@ -69,7 +69,7 @@ export class TanStackFieldComponent<
6969
constructor() {
7070
super()
7171
effect(() => {
72-
this.base.api.set(this.api)
72+
this.base._api.set(this.api)
7373
})
7474
}
7575
}

packages/angular-form/src/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
export * from '@tanstack/form-core'
22

3-
export { TanStackFieldComponent } from './app-field.component'
3+
export { TanStackAppField } from './app-field'
44
export { injectForm } from './inject-form'
5-
export { TanStackField } from './tanstack-field.directive'
5+
export { TanStackField } from './tanstack-field'
66
export { injectStore } from './inject-store'
77
export { TanStackFieldInjectable, injectField } from './injectable'

packages/angular-form/src/injectable.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { FieldApi } from '@tanstack/form-core'
33

44
@Injectable({ providedIn: null })
55
export class TanStackFieldInjectable<T> {
6-
api = signal<
6+
_api = signal<
77
FieldApi<
88
any,
99
any,
@@ -26,6 +26,10 @@ export class TanStackFieldInjectable<T> {
2626
any
2727
>
2828
>(null as never)
29+
30+
get api() {
31+
return this._api()
32+
}
2933
}
3034

3135
export function injectField<T>(): TanStackFieldInjectable<T> {
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import { render } from '@testing-library/angular'
2+
import { ChangeDetectionStrategy, Component, input } from '@angular/core'
3+
import { describe, expect, it } from 'vitest'
4+
import {
5+
TanStackAppField,
6+
TanStackField,
7+
injectField,
8+
injectForm,
9+
} from '../src/index'
10+
11+
describe('TanStackAppField', () => {
12+
it('should render a field with the correct label and default value', async () => {
13+
@Component({
14+
selector: 'app-text-field',
15+
changeDetection: ChangeDetectionStrategy.OnPush,
16+
standalone: true,
17+
template: `
18+
<label [for]="field.api.name">{{ label() }}</label>
19+
<input
20+
[id]="field.api.name"
21+
[name]="field.api.name"
22+
[value]="field.api.state.value"
23+
(blur)="field.api.handleBlur()"
24+
(input)="field.api.handleChange($any($event).target.value)"
25+
/>
26+
`,
27+
})
28+
class AppTextField {
29+
label = input.required<string>()
30+
field = injectField<string>()
31+
}
32+
33+
@Component({
34+
selector: 'app-root',
35+
standalone: true,
36+
changeDetection: ChangeDetectionStrategy.OnPush,
37+
imports: [TanStackField, TanStackAppField, AppTextField],
38+
template: `
39+
<form (submit)="handleSubmit($event)">
40+
<app-text-field
41+
label="Last name:"
42+
tanstack-app-field
43+
[tanstackField]="form"
44+
name="lastName"
45+
/>
46+
</form>
47+
`,
48+
})
49+
class AppComponent {
50+
form = injectForm({
51+
defaultValues: {
52+
firstName: '',
53+
lastName: 'Doe',
54+
},
55+
onSubmit({ value }) {
56+
console.log(value)
57+
},
58+
})
59+
60+
handleSubmit(event: SubmitEvent) {
61+
event.preventDefault()
62+
event.stopPropagation()
63+
this.form.handleSubmit()
64+
}
65+
}
66+
67+
const { getByLabelText } = await render(AppComponent)
68+
69+
const ourInput = getByLabelText('Last name:')
70+
expect(ourInput).toBeInTheDocument()
71+
expect(ourInput).toHaveValue('Doe')
72+
})
73+
})

0 commit comments

Comments
 (0)