- @if (!form.controls.sameAsShipping.value) {
-
-
-
-
-
+ @if (!form.sameAsShipping().value()) {
+
}
-
- {{ form.invalid ? 'Form incomplete' : 'Ready to submit' }}
+
+ {{ form().invalid() ? 'Form incomplete' : 'Ready to submit' }}
@@ -230,59 +144,61 @@ type CheckoutForm = {
],
})
export class AppComponent {
- readonly shipping: AddressGroup = this.createAddressGroup();
- readonly billing: AddressGroup = this.createAddressGroup();
+ model = signal({
+ firstName: '',
+ lastName: '',
+ shipping: {
+ street: '',
+ zipcode: '',
+ city: '',
+ },
+ billing: {
+ street: '',
+ zipcode: '',
+ city: '',
+ },
+ sameAsShipping: false,
+ });
- readonly form = new FormGroup({
- firstName: new FormControl('', {
- nonNullable: true,
- validators: [Validators.required],
- }),
- lastName: new FormControl('', {
- nonNullable: true,
- validators: [Validators.required],
- }),
- shipping: this.shipping,
- billing: this.billing,
- sameAsShipping: new FormControl(false, { nonNullable: true }),
+ form = form(this.model, (schema) => {
+ required(schema.firstName);
+ required(schema.lastName);
+ required(schema.billing, {
+ when: ({ valueOf }) => valueOf(schema.sameAsShipping),
+ });
+ apply(schema.shipping, this.addressSchema);
+ apply(schema.billing, this.addressSchema);
+ disabled(schema.billing, ({ valueOf }) => valueOf(schema.sameAsShipping));
});
- toggleSameAsShipping(): void {
- const checked = !this.form.controls.sameAsShipping.value;
- this.form.controls.sameAsShipping.setValue(checked, { emitEvent: false });
- if (checked) {
- this.billing.setValue(this.shipping.getRawValue(), { emitEvent: false });
- this.billing.disable({ emitEvent: false });
- } else {
- this.billing.enable({ emitEvent: false });
- }
- }
+ constructor() {
+ effect(() => {
+ const checked = this.form.sameAsShipping().value();
- onSubmit(): void {
- this.form.markAllAsTouched();
- if (this.form.invalid) {
- return;
- }
+ if (checked) {
+ untracked(() => {
+ this.form.billing().value.set(this.form.shipping().value());
+ });
+ }
+ });
}
- showError(control: FormControl): boolean {
- return control.invalid && (control.touched || control.dirty);
+ addressSchema(item: SchemaPathTree) {
+ required(item.street);
+ required(item.zipcode);
+ required(item.city);
}
- private createAddressGroup(): AddressGroup {
- return new FormGroup({
- street: new FormControl('', {
- nonNullable: true,
- validators: [Validators.required],
- }),
- zipcode: new FormControl('', {
- nonNullable: true,
- validators: [Validators.required],
- }),
- city: new FormControl('', {
- nonNullable: true,
- validators: [Validators.required],
- }),
+ async onSubmit($event: Event): Promise {
+ // TODO: to be removed in 21.2 and replaced by formRoot directive
+ $event.preventDefault();
+
+ await submit(this.form, async () => {
+ // TODO: add submit logic
});
}
+
+ showError(field: FieldState): boolean {
+ return field.invalid() && (field.touched() || field.dirty());
+ }
}