I was hoping to create a component that serves two purposes because the code behind is the same.
So I decided to use ng-template.
The first part is a modal popup and the html looks like this:
<div class="modal fade" #modal="mdbModal" tabindex="-1" role="dialog" aria-labelledby="myBasicModalLabel"
aria-hidden="true" mdbModal ng-if="!static && saveForm">
<div class="modal-dialog">
<div class="modal-content">
<form class="card" [formGroup]="saveForm" (ngSubmit)="onSubmit()">
<div class="modal-header">
<h4 class="modal-title pull-left">Are you sure?</h4>
<button type="button" class="close pull-right" aria-label="Close" (click)="modal.hide()">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<div *ngTemplateOutlet="form"></div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" (click)="modal.hide()">Cancel</button>
<button type="submit" class="btn btn-primary" (click)="modal.hide()">Save</button>
</div>
</form>
</div>
</div>
</div>
The second part is the static form, which looks like this:
<form class="card" [formGroup]="saveForm" (ngSubmit)="onSubmit()" [ngClass]="{ 'mb-0': modal }"
*ngIf="static && saveForm">
<div class="card-header">
<h3 class="card-title">{{editing ? 'Update': 'Create'}} your filter</h3>
</div>
<div class="card-body p-6">
<div *ngTemplateOutlet="form"></div>
</div>
<div class="card-footer text-right">
<div class="d-flex">
<a routerLink="/feeds" class="btn btn-link" *ngIf="!modal">Back</a>
<button type="submit" class="btn btn-primary ml-auto">Save</button>
</div>
</div>
</form>
and the template they share looks like this:
<ng-template #form>
<div class="form-group">
<label class="form-label" for="name">Name</label>
<input type="text" class="form-control" formControlName="name" placeholder="Enter the filter name"
[ngClass]="{ 'is-invalid': submitted && f.name.errors }" />
<div *ngIf="submitted && f.name.errors" class="invalid-feedback">
<div *ngIf="f.name.errors.required">
Name is required
</div>
</div>
</div>
<div class="form-group">
<label class="form-label" for="name">Field name</label>
<input type="text" class="form-control" formControlName="fieldName" placeholder="Enter the field name"
[ngClass]="{ 'is-invalid': submitted && f.fieldName.errors }" />
<div *ngIf="submitted && f.fieldName.errors" class="invalid-feedback">
<div *ngIf="f.fieldName.errors.required">
Field name is required
</div>
</div>
</div>
<div class="form-group">
<label class="form-label" for="image">Operator</label>
<select class="form-control" formControlName="filterOperator"
[ngClass]="{ 'is-invalid': submitted && f.filterOperator.errors }">
<option value="8">Between</option>
<option value="2">Equal</option>
<option value="4">Greater than</option>
<option value="6">Less than</option>
<option value="0">Like</option>
<option value="9">Not between</option>
<option value="3">Not equal</option>
<option value="5">Not greater than</option>
<option value="7">Not less than</option>
<option value="1">Not like</option>
<option value="10">Regular expression</option>
</select>
<div *ngIf="submitted && f.filterOperator.errors" class="invalid-feedback">
<div *ngIf="f.filterOperator.errors.required">
Operator is required
</div>
</div>
</div>
<div class="form-group">
<label class="form-label" for="name">Expression</label>
<input type="text" class="form-control" formControlName="expression" placeholder="Enter the expression"
[ngClass]="{ 'is-invalid': submitted && f.expression.errors }" />
<div *ngIf="submitted && f.expression.errors" class="invalid-feedback">
<div *ngIf="f.expression.errors.required">
Expression is required
</div>
</div>
</div>
</ng-template>
I was hoping this would just work, but I get an error stating:
formControlName must be used with a parent formGroup directive. You'll want to add a formGroup directive and pass it an existing FormGroup instance (you can create one in your class).
Which is annoying. Does anyone know how I can solve this issue?
here is the entire html:
<div class="modal fade" #modal="mdbModal" tabindex="-1" role="dialog" aria-labelledby="myBasicModalLabel"
aria-hidden="true" mdbModal ng-if="!static && saveForm">
<div class="modal-dialog">
<div class="modal-content">
<form class="card" [formGroup]="saveForm" (ngSubmit)="onSubmit()">
<div class="modal-header">
<h4 class="modal-title pull-left">Are you sure?</h4>
<button type="button" class="close pull-right" aria-label="Close" (click)="modal.hide()">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<div *ngTemplateOutlet="form"></div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" (click)="modal.hide()">Cancel</button>
<button type="submit" class="btn btn-primary" (click)="modal.hide()">Save</button>
</div>
</form>
</div>
</div>
</div>
<form class="card" [formGroup]="saveForm" (ngSubmit)="onSubmit()" [ngClass]="{ 'mb-0': modal }"
*ngIf="static && saveForm">
<div class="card-header">
<h3 class="card-title">{{editing ? 'Update': 'Create'}} your filter</h3>
</div>
<div class="card-body p-6">
<div *ngTemplateOutlet="form"></div>
</div>
<div class="card-footer text-right">
<div class="d-flex">
<a routerLink="/feeds" class="btn btn-link" *ngIf="!modal">Back</a>
<button type="submit" class="btn btn-primary ml-auto">Save</button>
</div>
</div>
</form>
<ng-template #form>
<div class="form-group">
<label class="form-label" for="name">Name</label>
<input type="text" class="form-control" formControlName="name" placeholder="Enter the filter name"
[ngClass]="{ 'is-invalid': submitted && f.name.errors }" />
<div *ngIf="submitted && f.name.errors" class="invalid-feedback">
<div *ngIf="f.name.errors.required">
Name is required
</div>
</div>
</div>
<div class="form-group">
<label class="form-label" for="name">Field name</label>
<input type="text" class="form-control" formControlName="fieldName" placeholder="Enter the field name"
[ngClass]="{ 'is-invalid': submitted && f.fieldName.errors }" />
<div *ngIf="submitted && f.fieldName.errors" class="invalid-feedback">
<div *ngIf="f.fieldName.errors.required">
Field name is required
</div>
</div>
</div>
<div class="form-group">
<label class="form-label" for="image">Operator</label>
<select class="form-control" formControlName="filterOperator"
[ngClass]="{ 'is-invalid': submitted && f.filterOperator.errors }">
<option value="8">Between</option>
<option value="2">Equal</option>
<option value="4">Greater than</option>
<option value="6">Less than</option>
<option value="0">Like</option>
<option value="9">Not between</option>
<option value="3">Not equal</option>
<option value="5">Not greater than</option>
<option value="7">Not less than</option>
<option value="1">Not like</option>
<option value="10">Regular expression</option>
</select>
<div *ngIf="submitted && f.filterOperator.errors" class="invalid-feedback">
<div *ngIf="f.filterOperator.errors.required">
Operator is required
</div>
</div>
</div>
<div class="form-group">
<label class="form-label" for="name">Expression</label>
<input type="text" class="form-control" formControlName="expression" placeholder="Enter the expression"
[ngClass]="{ 'is-invalid': submitted && f.expression.errors }" />
<div *ngIf="submitted && f.expression.errors" class="invalid-feedback">
<div *ngIf="f.expression.errors.required">
Expression is required
</div>
</div>
</div>
</ng-template>
You should pass the formGroup
to the template:
<ng-template #form let-form="form">
<div [formGroup]="form">
...
</div>
</ng-template>
And then call it this way:
<ng-container *ngTemplateOutlet="form; context: {form: saveForm}"></ng-container>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With