diff --git a/src/app/address/address.component.html b/src/app/address/address.component.html new file mode 100644 index 0000000..c59fb36 --- /dev/null +++ b/src/app/address/address.component.html @@ -0,0 +1,15 @@ +
+ {{ legend }} + + + +
diff --git a/src/app/address/address.component.scss b/src/app/address/address.component.scss new file mode 100644 index 0000000..e69de29 diff --git a/src/app/address/address.component.ts b/src/app/address/address.component.ts new file mode 100644 index 0000000..23f1c76 --- /dev/null +++ b/src/app/address/address.component.ts @@ -0,0 +1,74 @@ +import { + ChangeDetectionStrategy, + Component, + forwardRef, + Input, + OnDestroy, +} from '@angular/core'; +import { + AbstractControl, + ControlValueAccessor, + FormBuilder, + NG_VALIDATORS, + NG_VALUE_ACCESSOR, + ValidationErrors, + Validator, + Validators, +} from '@angular/forms'; +import { Subscription } from 'rxjs'; + +@Component({ + selector: 'ako-address', + templateUrl: './address.component.html', + styleUrls: ['./address.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => AddressComponent), + multi: true, + }, + { + provide: NG_VALIDATORS, + useExisting: forwardRef(() => AddressComponent), + multi: true, + }, + ], +}) +export class AddressComponent + implements OnDestroy, ControlValueAccessor, Validator +{ + @Input() legend = ''; + + form = this.fb.group({ + line1: ['', Validators.required], + city: '', + zipCode: '', + }); + + private sub?: Subscription; + onTouchedCb?: () => void; + + constructor(private fb: FormBuilder) {} + + validate(control: AbstractControl): ValidationErrors | null { + return this.form.valid ? null : { invalidAddress: true }; + } + + writeValue(obj: any): void { + obj && this.form.setValue(obj, { emitEvent: false }); + } + registerOnChange(fn: any): void { + this.sub = this.form.valueChanges.subscribe(fn); + } + registerOnTouched(fn: any): void { + this.onTouchedCb = fn; + } + setDisabledState?(isDisabled: boolean): void { + isDisabled ? this.form.disable() : this.form.enable(); + } + + ngOnDestroy(): void { + this.sub?.unsubscribe(); + } +} diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 7c38c43..f3b39cc 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -2,7 +2,10 @@ import { ChangeDetectionStrategy, Component } from '@angular/core'; @Component({ selector: 'ako-root', - template: '', + template: ` + + + `, styles: [ ` :host { diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 0530101..ff73b7e 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -1,13 +1,15 @@ import { NgModule } from '@angular/core'; -import { FormsModule } from '@angular/forms'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { BrowserModule } from '@angular/platform-browser'; import { AppComponent } from './app.component'; +import { CheckoutReactiveComponent } from './checkout-reactive/checkout-reactive.component'; import { CheckoutComponent } from './checkout/checkout.component'; +import { AddressComponent } from './address/address.component'; @NgModule({ - declarations: [AppComponent, CheckoutComponent], - imports: [BrowserModule, FormsModule], + declarations: [AppComponent, CheckoutComponent, CheckoutReactiveComponent, AddressComponent], + imports: [BrowserModule, FormsModule, ReactiveFormsModule], bootstrap: [AppComponent], }) export class AppModule {} diff --git a/src/app/checkout-reactive/checkout-reactive.component.html b/src/app/checkout-reactive/checkout-reactive.component.html new file mode 100644 index 0000000..08b4036 --- /dev/null +++ b/src/app/checkout-reactive/checkout-reactive.component.html @@ -0,0 +1,29 @@ +
+ + + + + + +
+ +
+Reactive
+
+FormGroup.value:
+{{ form.value | json }}
+
+Status: {{ form.status }}
+
diff --git a/src/app/checkout-reactive/checkout-reactive.component.scss b/src/app/checkout-reactive/checkout-reactive.component.scss new file mode 100644 index 0000000..8c5e73d --- /dev/null +++ b/src/app/checkout-reactive/checkout-reactive.component.scss @@ -0,0 +1,30 @@ +:host { + width: 100%; + margin-top: var(--half-separation); + display: grid; + grid-template-columns: 1fr; + gap: var(--base-separation); + justify-content: center; +} + +form { + width: 460px; +} + +pre { + display: none; + padding: var(--double-separation); + background-color: white; + border-radius: 8px; +} + +@media screen and (min-width: 920px) { + :host { + flex-direction: row; + grid-template-columns: 1fr 1fr; + } + + pre { + display: block; + } +} diff --git a/src/app/checkout-reactive/checkout-reactive.component.ts b/src/app/checkout-reactive/checkout-reactive.component.ts new file mode 100644 index 0000000..11fd09f --- /dev/null +++ b/src/app/checkout-reactive/checkout-reactive.component.ts @@ -0,0 +1,29 @@ +import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core'; +import { FormBuilder } from '@angular/forms'; + +@Component({ + selector: 'ako-checkout-reactive', + templateUrl: './checkout-reactive.component.html', + styleUrls: ['./checkout-reactive.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class CheckoutReactiveComponent implements OnInit { + form = this.fb.group({ + fullName: '', + email: '', + deliveryAddress: { + line1: '', + city: '', + zipCode: '', + }, + billingAddress: { + line1: '', + city: '', + zipCode: '', + }, + }); + + constructor(private fb: FormBuilder) {} + + ngOnInit(): void {} +} diff --git a/src/app/checkout/checkout.component.html b/src/app/checkout/checkout.component.html index 116d14b..fe12687 100644 --- a/src/app/checkout/checkout.component.html +++ b/src/app/checkout/checkout.component.html @@ -7,36 +7,16 @@ Correo Electrónico -
- Dirección de Entrega - - - -
-
- Dirección de Facturación - - - -
+ +