Ninja Space Content Tech Blog

Week Five of Learning Angular

Posted by Ninja Space Content on Sunday, April 11, 2021 Under: angular
I am now getting into forms using the Programming with Mosh's Angular Tutorial. I'm in my 5th week of learning Angular and focusing this blog entry on the introduction to forms and narrowing in on Template-driven Forms. Click here to see my weekly breakdown of learning Angular.

Forms
In Angular, it is a requirement to write a div with a class of form-group for any forms like so:

 <div class="form-group">
    <label for="firstName"></label>
    <input id="firstName" type="text" class="form-control">
    </div>  

Zen Coding
One of the amazing things that I learned is zen coding from Mosh as I am going through this Angular tutorial. You can type something like the following: 

div.form-group>label[for='comment']+textarea[id='comment'].form-control and click tab, and you'll get the mark ups needed quickly for html. Then, this will generate the following: 

<div class="form-group"><label for="comment"></label><textarea name="" id="comment" cols="30" rows="10" class="form-control"></textarea></div>


Form Control
Angular has a class called FormControl and you can check the following: value, touched, untouched, dirty, pristine, valid and errors.

Form Group
FormGroup is a class that represents a group of controls in a form. All the attributes from the Form Control can also be seen from Form Group, which includes: value, touched, dirty, pristine, valid and errors.

You need 1 Form Group for a form and each input field has a Form Control to keep in track for each state of fields.

There are 2 types of forms: Reactive (previously called model-driven form) and Template-driven (with directives).  Reactive is good for complex forms. Template-driven is great for simple forms and easier to code with less code.

FormsModule
I received this error message when I was working with Forms: No directive found with exportAs 'ngModel'. What I had to do to use the ngModel directive in my html file is to go to my app.module.ts file and import {FormsModule} from '@angular/forms'; and also make sure I added it under the imports: array. That way I was able to implement this form below without compiling errors.

<form>
    <div class="form-group">
        <label for="firstName">First Name</label>
        <input ngModel name="firstName" #firstName="ngModel" (change)="log(firstName)" id="firstName" type="text" class="form-control">
    </div>  

    <div class="form-group">
        <label for="comment">Comment</label>
        <textarea ngModel name="comment" id="comment" cols="30" rows="10" class="form-control"></textarea>
    </div>

    <button class="btn btn-primary">Submit</button>
</form>

Adding Validation
You can add input validation alerts like so: <div class="alert alert-danger" *ngIf="firstName.touched && !firstName.valid">First Name is required.</div>

Error for Using *ngIf for Forms
I was following Programming with Mosh's tutorial line by line and for my typescript version, I kept getting this error: Object is possibly 'null'.

After digging into Stack Overflow, it's because with Mosh's typescript version, it wasn't an issue. For me I had to add the following conditional with an && to get the compiling error to go away : 
<div *ngIf="firstName.errors">First Name is required.</div>
<div *ngIf="firstName.errors && firstName.errors.minlength">First name should be minimum 3 characters</div>

After debugging for a little while, here's the working code below: 
  <div class="form-group">
        <label for="firstName">First Name</label>
        <input required minlength="4" maxlength="10" pattern="luis" ngModel name="firstName" #firstName="ngModel" (change)="log(firstName)" id="firstName" type="text" class="form-control">
        <div class="alert alert-danger" *ngIf="firstName.touched && !firstName.valid">
            <div *ngIf="firstName.errors && firstName.errors.required">First Name is required.</div>
            <div *ngIf="firstName.errors && firstName.errors.minlength">First name should be minimum {{firstName.errors.minlength.requiredLength}} characters</div>
            <div *ngIf="firstName.errors && firstName.errors.pattern">First name does not match pattern.</div>
            Error!
        </div>
    </div>
Form Classes 
Built into Angular are other classes like ng-form-control, ng-invalid, ng-touched and ng-dirty. To change the styling on your input when a user's input does not meet the criterias, you can utilized these classes to your advantage. Ex for styling: 

.form-control.ng-touched.ng-invalid { border: 2px solid red; }


ngForm Directive
You can also use ngForm to utilize the values of the properties and test by console logging it.

Template-driven Form Example
Here is a great full form example below starting with ts file under that component folder:

export class NewCourseFormComponent implements OnInit {
  categories = [
    {id: 1, name: 'Development' },
    {id: 2, name: 'Art' },
    {id: 3, name: 'Languages' },
  ]
  constructor() { }

  submit(course: any) {
    console.log(course)
  }

  ngOnInit(): void {
  }

Then, in html file:

<form #f="ngForm" (ngSubmit)="submit(f.value)">  
    <div class="form-group">
        <label for="name">Course Name</label>
        <input required minlength="3" ngModel name="name" #name="ngModel" type="text" id="name" class="form-control">
        <div *ngIf="name.touched && name.invalid"></div>
            <div *ngIf="name.errors && name.errors.required">Name field is required.</div>
            <div *ngIf="name.errors && name.errors.minlength">Min length should be {{name.errors.minlength.requiredLength}} characters</div>
    </div>
    <div class="form-group">
        <label for="category">Category</label>
        <select required ngModel name="category" #category="ngModel" id="category" class="form-control">
            <option value=""></option>
            <option *ngFor="let category of categories" 
            [value]='category.id'
            >{{category.name}}</option>
        </select>
        <div *ngIf="category.touched && category.invalid">
            Category field is required
        </div>
    </div>
    <div class="checkbox">
        <label for="moneyBackGuarantee">
            <input ngModel name="hasMoneyBackGuarantee" type="checkbox" id="moneyBackGuarantee" class="form-control">
            30-day money back guarantee?
        </label>
    </div>
    <p>{{f.value | json }}

    </p>
    <button [disabled]="f.invalid" >Create</button>
</form>

In : angular 


Tags: learning angular  angular notes for newbies  noob 

About Ninja Space Content


Ninja Space Content I have been building simple websites on my own since 2008 and currently run several websites at the moment, including this one. I used to be an account manager for an affiliate/e-commerce company, helping affiliates grow their sales so I have some knowledge on the business side and client side of affiliate marketing. During the Covid-19 pandemic, I completed a JavaScript coding bootcamp and graduated in Dec 2020. I've been working as a contractor for a few software companies ever since.
Note: links to resources and promoting special deals may allow me to earn a small commission from each sale.