@@ -79,14 +79,18 @@ Within the component where the (top) form will be handled, you have to define th
7979Before explaining the difference between ` NgxRootFormComponent ` or ` NgxAutomaticRootFormComponent ` , let's look at an example with a polymorphic type:
8080
8181``` ts
82+ // src/readme/listing.component.ts#L8-L58
83+
8284enum ListingType {
8385 VEHICLE = ' Vehicle' ,
8486 DROID = ' Droid' ,
8587}
8688
87- interface OneListingForm {
89+ export interface OneListingForm {
90+ id: string ;
8891 title: string ;
8992 price: number ;
93+ imageUrl: string ;
9094
9195 // polymorphic form where product can either be a vehicle or a droid
9296 listingType: ListingType | null ;
@@ -99,17 +103,19 @@ interface OneListingForm {
99103 templateUrl: ' ./listing.component.html' ,
100104 styleUrls: [' ./listing.component.scss' ],
101105})
102- export class ListingComponent extends NgxAutomaticRootFormComponent <OneListingForm > {
106+ export class ListingComponent extends NgxAutomaticRootFormComponent <OneListing , OneListingForm > {
103107 // as we're renaming the input, it'd be impossible for ngx-sub-form to guess
104108 // the name of your input to then check within the `ngOnChanges` hook wheter
105109 // it has been updated or not
106110 // another solution would be to ask you to use a setter and call a hook but
107111 // this is too verbose, that's why we created a decorator `@DataInput`
108112 @DataInput ()
113+ // tslint:disable-next-line:no-input-rename
109114 @Input (' listing' )
110115 public dataInput: OneListing | null | undefined ;
111116
112- public @Output (' listingUpdated' ) dataOutput: EventEmitter <OneListingForm > = new EventEmitter ();
117+ // tslint:disable-next-line:no-output-rename
118+ @Output (' listingUpdated' ) public dataOutput: EventEmitter <OneListing > = new EventEmitter ();
113119
114120 // to access it from the view
115121 public ListingType = ListingType ;
@@ -135,9 +141,11 @@ Then, within the `.component.html` we:
135141- Use ` ngSwitch ` directive to create either a ` DroidProductComponent ` or a ` VehicleProductComponent `
136142
137143``` html
144+ <!-- src/readme/listing.component.html -->
145+
138146<form [formGroup] =" formGroup" >
139147 <select [formControlName] =" formControlNames.listingType" >
140- <option *ngFor =" let listingType of ListingType | keyvalue" [value] =" listingType.value" >
148+ <option *ngFor =" let listingType of ( ListingType | keyvalue) " [value] =" listingType.value" >
141149 {{ listingType.value }}
142150 </option >
143151 </select >
@@ -163,6 +171,8 @@ Every time the form changes, that component will `emit` a value from the `dataOu
163171From the parent component you can do like the following:
164172
165173``` html
174+ <!-- src/readme/listing-form-usage.html -->
175+
166176<app-listing-form
167177 [disabled] =" false"
168178 [listing] =" listing$ | async"
@@ -180,6 +190,8 @@ Differences between:
180190The method ` handleEmissionRate ` is available accross ** all** the classes that ` ngx-sub-form ` offers. It takes an observable as input and expect another observable as output. One common case is to simply [ ` debounce ` ] ( http://reactivex.io/rxjs/class/es6/Observable.js~Observable.html#instance-method-debounce ) the emission. If that's what you want to do, instead of manipulating the observable chain yourself you can just do:
181191
182192``` ts
193+ // src/readme/handle-emission-rate.ts#L6-L9
194+
183195protected handleEmissionRate (): (obs$ : Observable <OneListingForm >) => Observable < OneListingForm > {
184196 // debounce by 500ms
185197 return NGX_SUB_FORM_HANDLE_VALUE_CHANGES_RATE_STRATEGIES.debounce(500 );
@@ -194,37 +206,28 @@ All you have to do is:
194206
1952071 . Add required providers using the utility function ` subformComponentProviders ` :
196208
197- ``` diff
198- + import { subformComponentProviders } from 'ngx-sub-form';
209+ ``` ts
210+ // src/readme/steps/add-providers.ts#L2-L10
211+
212+ import { subformComponentProviders } from ' ngx-sub-form' ;
199213
200214@Component ({
201215 selector: ' app-vehicle-product' ,
202216 templateUrl: ' ./vehicle-product.component.html' ,
203217 styleUrls: [' ./vehicle-product.component.scss' ],
204- + providers: subformComponentProviders(VehicleProductComponent),
218+ providers: subformComponentProviders (VehicleProductComponent ), // <-- Add this
205219})
206220export class VehicleProductComponent {}
207221```
208222
2092232 . Make your original class extend ` NgxSubFormComponent ` ** or** ` NgxSubFormRemapComponent ` if you need to remap the data (will be explained later):
210-
211- ``` diff
212- + import { subformComponentProviders } from 'ngx-sub-form';
213-
214- @Component({
215- selector: 'app-vehicle-product',
216- templateUrl: './vehicle-product.component.html',
217- styleUrls: ['./vehicle-product.component.scss'],
218- + providers: subformComponentProviders(VehicleProductComponent),
219- })
220- + export class VehicleProductComponent extends NgxSubFormComponent {}
221- ```
222-
223- Define the controls of your form (as we previously did in the top form component):
224+ 3 . Implement the required interface by defining the controls of your form (as we previously did in the top form component):
224225
225226``` ts
227+ // src/readme/steps/add-controls.ts#L12-L20
228+
226229export class VehicleProductComponent extends NgxSubFormComponent <OneVehicleForm > {
227- protected getFormControls(): Controls <OneVehicle > {
230+ protected getFormControls(): Controls <OneVehicleForm > {
228231 return {
229232 speeder: new FormControl (null ),
230233 spaceship: new FormControl (null ),
@@ -244,9 +247,11 @@ which will require you to define two interfaces:
244247- One to model the data going into the form
245248- The other to describe the data that will be set as the value
246249
247- Example, take a look into [ ` VehicleProductComponent ` ] ( https://github.com/cloudnc/ngx-sub-form/blob/master/src/app/main/listing/listing-form/vehicle-listing/vehicle-product.component.ts ) :
250+ Example, take a look at [ ` VehicleProductComponent ` ] ( https://github.com/cloudnc/ngx-sub-form/blob/master/src/app/main/listing/listing-form/vehicle-listing/vehicle-product.component.ts ) :
248251
249252``` ts
253+ // src/readme/vehicle-product.component.simplified.ts#L7-L69
254+
250255// merged few files together to make it easier to follow
251256export interface BaseVehicle {
252257 color: string ;
@@ -317,10 +322,12 @@ export class VehicleProductComponent extends NgxSubFormRemapComponent<OneVehicle
317322For a complete example of this see ` https://github.com/cloudnc/ngx-sub-form/blob/master/src/app/main/listing/listing-form/vehicle-listing/vehicle-product.component.ts ` (repeated below):
318323
319324``` ts
320- interface OneVehicleForm {
321- speeder: Speeder ;
322- spaceship: Spaceship ;
323- vehicleType: VehicleType ;
325+ // src/app/main/listing/listing-form/vehicle-listing/vehicle-product.component.ts#L7-L50
326+
327+ export interface OneVehicleForm {
328+ speeder: Speeder | null ;
329+ spaceship: Spaceship | null ;
330+ vehicleType: VehicleType | null ;
324331}
325332
326333@Component ({
@@ -330,14 +337,16 @@ interface OneVehicleForm {
330337 providers: subformComponentProviders (VehicleProductComponent ),
331338})
332339export class VehicleProductComponent extends NgxSubFormRemapComponent <OneVehicle , OneVehicleForm > {
333- protected formControls: Controls <OneVehicleForm > = {
334- speeder: new FormControl (null ),
335- spaceship: new FormControl (null ),
336- vehicleType: new FormControl (null , { validators: [Validators .required ] }),
337- };
338-
339340 public VehicleType = VehicleType ;
340341
342+ protected getFormControls(): Controls <OneVehicleForm > {
343+ return {
344+ speeder: new FormControl (null ),
345+ spaceship: new FormControl (null ),
346+ vehicleType: new FormControl (null , { validators: [Validators .required ] }),
347+ };
348+ }
349+
341350 protected transformToFormGroup(obj : OneVehicle ): OneVehicleForm {
342351 return {
343352 speeder: obj .vehicleType === VehicleType .SPEEDER ? obj : null ,
@@ -346,12 +355,16 @@ export class VehicleProductComponent extends NgxSubFormRemapComponent<OneVehicle
346355 };
347356 }
348357
349- protected transformFromFormGroup(formValue : OneVehicleForm ): OneVehicle {
358+ protected transformFromFormGroup(formValue : OneVehicleForm ): OneVehicle | null {
350359 switch (formValue .vehicleType ) {
351360 case VehicleType .SPEEDER :
352361 return formValue .speeder ;
353362 case VehicleType .SPACESHIP :
354363 return formValue .spaceship ;
364+ case null :
365+ return null ;
366+ default :
367+ throw new UnreachableCase (formValue .vehicleType );
355368 }
356369 }
357370}
@@ -368,12 +381,20 @@ Our "incoming" object is of type `OneVehicle` but into that component we treat i
368381e.g.
369382
370383``` ts
384+ // src/readme/password-sub-form.component.ts#L5-L39
385+
371386interface PasswordForm {
372387 password: string ;
373388 passwordRepeat: string ;
374389}
375390
376- class PasswordSubComponent extends NgxSubFormComponent <PasswordForm > {
391+ @Component ({
392+ selector: ' app-password-sub-form' ,
393+ templateUrl: ' ./password-sub-form.component.html' ,
394+ styleUrls: [' ./password-sub-form.component.scss' ],
395+ providers: subformComponentProviders (PasswordSubFormComponent ),
396+ })
397+ class PasswordSubFormComponent extends NgxSubFormComponent <PasswordForm > {
377398 protected getFormControls() {
378399 return {
379400 password: new FormControl (null , [Validators .required , Validators .minLength (8 )]),
@@ -402,6 +423,8 @@ class PasswordSubComponent extends NgxSubFormComponent<PasswordForm> {
402423Errors are exposed under the key ` errors.formGroup ` e.g.
403424
404425``` html
426+ <!-- src/readme/password-sub-form.component.html -->
427+
405428<input type =" text" placeholder =" Password" [formControlName] =" formControlNames.password" />
406429<mat-error *ngIf =" formControlErrors?.password?.minlength" >Password too short</mat-error >
407430
0 commit comments