Sunday, July 2, 2017

Angular 4 Forms 101

Do note:

  1. You need to loop in the FormsModule at your module.
  2. You need to wrap form elements in form tags and the opening tag should be something like so:
    <form (ngSubmit)="whatever(x)" #x="ngForm">
  3. This allows for something like this:
    whatever(me: NgForm) {
       let foo = me.bar;
       let baz = me.qux;
  4. Above bar and qux are input fields inside the form tag and this trick slurps out their values. In order to get this to work the name attribute needs to go back into the form tag and it needs to be accompanied by ngModel too. Basically name="bar" ngModel and name="qux" ngModel need to go inside the form field tags.
  5. A submit type button like so may submit the form:
    <button type="submit" [disabled]="!x.valid">Go</button> ...and you'll notice the pseudovalidation. I'll get to the real validation stuff soon.
  6. To make the quasivalidation work at the bar and qux controls just add required inside their tags. If you need a more specific validation you can also put this inline in the tag to loop in regular expressions [pattern]="'^whatever$'"
  7. You may use the ViewChild trick to get #x into the TypeScript side of the component. Let's say it becomes a variable called w there. Well then, you may do something like this to set the values of bar and qux:
    this.w.setValue({
       bar: "cat",
       qux: "dog"
    });
  8. this.w.setValue.reset(); will reset our form.
  9. import { FormGroup } from '@angular/forms'; lets you bring in FormGroup for reactive forms. Make one inside the template class but outside any methods with v: FormGroup; and then make an assignment elsewhere like this:
    private stageForm() {
       this.v = new FormGroup({
          'myControl': new FormControl('default value here'),
          'somethingElse': new FormControl('make sense now?')
       });
    });

    Call stageForm(); above from ngOnInit. :)
  10. import { FormsModule, ReactiveFormsModule } from '@angular/forms'; needs to be looped in at your module for reactive forms.
  11. <form [fromGroup]="v"> is what the form tag will look like. The stuff you have between the open and close form tag, the HTML for form guts, kinda gets used as a template within your template. You may assign the controls you defined on the TypeScript side to controls therein. Put formControlName="myControl" and formControlName="somethingElse" inside of existing input tags (or textarea or select tags... whatever) to make this happen.
  12. Loop in FormArray of angular/forms to have some multirow content in your form. You may "new up" (instantiate) one like so:
    let gadgets = new FormArray([]);
    gadgets.push(
       new FormGroup({
          'torque': new FormControl('13'),
          'gauge': new FormControl('42')
       });
    );

    Then inside of a form, let's use our v form, you may loop through the array at the template like so:
    <div *ngFor="let gadget of v.get('stuff').controls; let i=index"
          [formGroupName]="i">

    What is stuff you ask? Well, that is a good question. You will need to revamp the setup of v like so:
    private stageForm() {
       this.v = new FormGroup({
          'myControl': new FormControl('default value here'),
          'somethingElse': new FormControl('make sense now?'),
          'stuff': gadgets
       });
    });

    Alright, at the loop template inside of the form template inside of the component template (it's all the same file) you will need to use the formControlName trick to assign torque and gauge to controls.
  13. (<FormArray>this.v.get('stuff')).push(
       new FormGroup({
          'torque': new FormControl(),
          'gauge': new FormControl()
       });
    );
    would be an example of adding a new row to the form rows after the fact. This one has no values, it would be of a fill-in-a-new-record flavor.
  14. Loop in Validators of angular/forms to do... validations! You'll set them up like so, and yes this is something different than disabling the submit button:
    private stageForm() {
       this.v = new FormGroup({
          'myControl': new FormControl('default value here', Validators.required),
          'somethingElse': new FormControl(null [
             Validators.required,
             Validators.pattern(/^
    whatever$/)
          ])
       });
    });
    and how this will take shape was a bit of a surprise to me. You will notice that we are not including an error message in the validation code so what is it going to tell us when things go South? Well this process is not going to cough up some copy in a new div sitting side by side with a control as you might expect in a web forms or an ASP.NET MVC approach. Instead it just gives the ng-invalid style to that which is invalid. You will not want to style .ng-invalid{ in your stylesheet however as this is too general and will style the whole of any form that has even one validation error. Instead try something like .input.ng-invalid.ng-touched{ wherein the first bit restrains your style at your stylesheet for the component to input tags and the end bit makes it so that if a control starts out empty it is not angry until you click in it and then continue to give nothing or the wrong sort of something.
  15. let slurpOut = this.v['myControl']; is an example pulling something back out of a form. The multirow thing can just fit to an array of a particular type.
  16. (<FormArray>this.v.get('stuff')).removeAt(myIndex); should be gold for dropping a row out of the rows. myIndex here would correspond to i handed into a TypeScript method from the template.

 
 

In learning this stuff I also learned:

  1. let y = new Subject<Whatever[]>(); is an example of an RxJS helper that one may loop in with:
    import { Subject } from 'rxjs/Subject';
  2. import { Subscription } from 'rxjs/Subscription'; will similarly loop in subscriptions. Make one inside the template class but outside any methods with z: Subscription; and then turn around and do a subscribe with something along the lines of maybe this.z = this.that.theotherthing.subscribe(); and do an unsubscribe to prevent a memory leak with this.z.unsubscribe();
  3. Router may be looped in from @angular/router and I don't really understand the routing yet. One may navigate up a folder like so:
    this.myRouter.navigate(['../'], { relativeTo: this.myRoute });

 
 

Addendum 12/19/2017: In bullet point eleven fromGroup should really be formGroup. Duh.

 
 

Addendum 3/28/2020: There should probably be a comma after the null in the code in bullet 14.

No comments:

Post a Comment