The goal is when a user clicks a button to go to the next page, prevent the user from continuing and display an error indicator if the page is partially filled out but not valid.
In a template-driven form, I have several container elements using the NgModelGroup attribute to represent a "page" in the form. In my component I want to reference this collection so I can access them with an index. Since I couldn't get this collection (@AJT_82 comments why below), this was my approach:
I made a class to hold info about a page.
export class Page
{
title: string;
hasError: boolean; //should the page display an error indicator
}
and in my component I populate an array, pages: Page[], in ngOnInit
ngOnInit()
{
this.pages = [{title: "Page 1", hasError: false},
{title: "Page 2", hasError: false},
{title: "Page 3", hasError: false}]
}
and @DeborahK in her answer gave me
this.form.form.get('pg1'))
to get the individual ngModelGroup named 'pg' + currentPg+1 (+1 to match the View since arrays starts at 0) that I could then use in a click event that will result in either A)going to the next page or B)setting the hasError property to true and not going to next page.
let p = this.form.form.get("pg"+ (this.currentPg+1));
//if the page is partially filled out but not valid
if(p.invalid && p.dirty)
this.pages[this.currentPg].hasError = true;
else
{
//even if it's false, re-false it ;)
this.pages[this.currentPg].hasError = false;
//continue to next page.
//i.e. this.currentPg++ or this.currentPg--
}
Back in the template, to show an error indicator on either the tab or the page I just check the pages[currentPg].hasError property. Assign "has-error" class on tab element for styling the tab.
<div id="tabs">
<a *ngFor="let p of pages"
[ngClass]="(p.hasError ? ' has-error' : '')"><p>{{p.title}}</p></a>
</div>
<form #f="ngForm">
<div ngModelGroup="pg1"> <!-- pages[0] -->
<div id="errorBlock" *ngIf="pages[currentPg].hasError">
You had an error.
</div>
<div>
<input ngModel/>
<input ngModel/>
</div>
<div>
<input ngModel/>
<input ngModel/>
</div>
</div>
<div ngModelGroup="pg2"> <!-- pages[1] -->
<input ngModel/>
</div>
</form>
and here's the example's component:
...
currentPg: number = 0;
pages: Page[] = [];
@ViewChild('f') public form: NgForm;
ngOnInit()
{
this.pages = [{title: "Page 1", hasError: false},
{title: "Page 2", hasError: false},
{title: "Page 3", hasError: false}]
}
NextPage()
{
let p = this.form.form.get("pg"+ (this.currentPg+1));
//if the page is partially filled out but not valid
if(p.invalid && p.dirty)
this.pages[this.currentPg].hasError = true;
else
{
//even if it's false, re-false it ;)
this.pages[this.currentPg].hasError = false;
//Do navigation logic.
//i.e. this.currentPg++ or this.currentPg--
}
}
Again, a lot of this can go away if there's a way to get the collection of ngModelGroups and use it like an array.