I have 2 components, namely register component and another is modify component. I want to bind the register components selected items into modify component. So how to bind the register components values into modify component.
I have written the code as below:
register.component.html
<mat-form-field class="full-width tag">
<mat-label class="full-width tag">Select Tag</mat-label>
<mat-select #select multiple formControlName="tags" [(ngModel)]="project.tags">
<mat-option (click)="optionClick()" *ngFor="let tag of tags" [value]="tag">
{{ tag }}
</mat-option>
</mat-select>
</mat-form-field>
register.component.ts
tags: any[] = ["Prod", "Stg", "Dev", "QA"];
optionClick() {
let newStatus = true;
this.select.options.forEach((item: MatOption) => {
if (!item.selected) {
newStatus = false;
}
});
}
register.model.ts
export class Project {
public tags;
}
modify.component.html
<mat-form-field class="full-width tag">
<mat-label class="full-width tag">Select Tag</mat-label>
<mat-select #select multiple formControlName="tags" [(ngModel)]="project.tags">
<mat-option (click)="optionClick()" *ngFor="let tag of tags" [value]="tag">
{{ tag }}
</mat-option>
</mat-select>
</mat-form-field>
Related
I'm trying to build a website which provides the functionality of uploading your own courses.
Course Structure
Name of course
|-Module1
|-Lecture1
|-Lecture2
|-Module2
|-Lecture1
|-Lecture2
Using Angular I'm trying to create a dynamic form which will add/remove modules within the course and lecture within a module
So far, I have written the following -
course-upload.component.ts
export class CourseUploadComponent implements OnInit {
courseUploadForm: FormGroup;
constructor(private formBuilder: FormBuilder) { }
ngOnInit() {
this.courseUploadForm = this.formBuilder.group({
coursename: ['', Validators.required],
modules: this.formBuilder.array([
this.initModules()
])
})
}
initModules() {
return this.formBuilder.group({
modulename: ['', Validators.required],
lectures: this.formBuilder.array([
this.initLecture()
])
});
}
initLecture() {
return this.formBuilder.group({
lecturename: ['', Validators.required],
description: ['', Validators.required],
lecture: ['', Validators.required]
});
}
addModule() {
const control = <FormArray>this.courseUploadForm.get('modules');
control.push(this.initModules());
}
addLecture() {
const control = <FormArray>this.courseUploadForm.get('lectures');
control.push(this.initLecture());
}
removeModule(i: number) {
const control = <FormArray>this.courseUploadForm.get('modules');
control.removeAt(i);
}
removeLecture(i: number) {
const control = <FormArray>this.courseUploadForm.get('lectures');
control.removeAt(i);
}
getModulesControls(i: number) {
>>>> return [(this.courseUploadForm.controls.modules as FormArray).controls[i]['controls']];
}
getLecturesControls(i: number) {
return [(this.courseUploadForm.controls.lectures as FormArray).controls[i]['controls']];
}
}
course-upload.component.html
<form [formGroup]="courseUploadForm" novalidate>
<div formArrayName="modules">
<mat-card *ngFor="let module of courseUploadForm.get('modules').value; let i=index">
<mat-card-subtitle>
{{i+1}}
</mat-card-subtitle>
<div [formGroupName]="i">
<mat-form-field>
<mat-label>Module Name</mat-label>
**>>>** <input matInput placeholder="Module Name" formControlName="modulename">
<ng-container *ngFor="let control of getModulesControls(j)">
<mat-error *ngIf="!control.name.valid">Name Required</mat-error>
</ng-container>
</mat-form-field>
<div formArrayName="lectures">
<mat-card *ngFor="let lecture of module.get('lectures').value; let j=index">
<mat-card-subtitle>
Lecture {{i+1}}: {{lecture.name}}
</mat-card-subtitle>
<div [formGroupName]="j">
<mat-form-field>
<mat-label>Name</mat-label>
<input matInput placeholder="Lecture Name" formControlName="lecturename">
<ng-container *ngFor="let control of getLecturesControls(j)">
<mat-error *ngIf="!control.name.valid">Name Required</mat-error>
</ng-container>
</mat-form-field>
<mat-form-field>
<mat-label>Description</mat-label>
<input matInput placeholder="Lecture Description" formControlName="description">
<ng-container *ngFor="let control of getLecturesControls(j)">
<mat-error *ngIf="!control.description.valid">Description Required</mat-error>
</ng-container>
</mat-form-field>
<mat-form-field>
<mat-label>Lecture</mat-label>
<input matInput placeholder="Lecture Video" formControlName="lecture">
<ng-container *ngFor="let control of getLecturesControls(j)">
<mat-error *ngIf="!control.lecture.valid">Lecture Video Required</mat-error>
</ng-container>
</mat-form-field>
<mat-card-actions>
<button mat-raised-button color="accent" (click)="addLecture()">Add Another
Lecture</button>
<button mat-raised-button color="warn"
*ngIf="module.get('lectures')['controls'].length > 1"
(click)="removeLecture(j)">Remove This Lecture</button>
</mat-card-actions>
</div>
</mat-card>
</div>
<mat-card-actions>
<button mat-raised-button color="accent" (click)="addModule()">Add Another Module</button>
<button mat-raised-button color="warn"
*ngIf="courseUploadForm.get('modules')['controls'].length > 1" (click)="removeModule(i)">Remove
This Module</button>
</mat-card-actions>
</div>
</mat-card>
</div>
</form>
I get the error:
Cannot read property 'controls' of undefined
at CourseUploadComponent.getModulesControls
at CourseUploadComponent_mat_card_2_Template
I've highlighted the lines that throw the error with ** > **
Some help?
j is not defined here it should have been smg different
<ng-container *ngFor="let control of getModulesControls(j)">
<mat-error *ngIf="!control.name.valid">Name Required</mat-error>
</ng-container>
I suppose you meant to use the variable i there: getModulesControls(i)
Also, line 5 of the HTML file the variable module is defined as an Object. Line 23 module.get('lectures') looks like you expect a FormGroup in the module variable. Take a look at this example from Angular docs. Pay attention to both HTML markup and TS. You will need to create several getters like get cities(): FormArray (:
I think you have to check your given array empty or not. If empty you should return null,
getModulesControls(i: number) {
if(this.courseUploadForm.controls.modules.length <1){
return null;
}
else{
return [(this.courseUploadForm.controls.modules as FormArray).controls[i]['controls']];
}
}
My question seems to be very similar to AWS - Using email template from S3 bucket except instead of Python, I am using java/springboot to send the email from AWS SES and using javascript/typescript for the front end. I'm able to send an email with a hardcoded subject and body. I want to be able to send an email with a template from my S3 bucket. My application has a list of the templates in the bucket. When selected, a preview is displayed. How can I send a selected template within my application?
# "send-email-templates.ts"
constructor(
private templateService: TemplateService,
private schoolService: SchoolService,
private hireStageService: HireStageService,
private emailSearchService: EmailSearchService,
private router: Router,
private _ngZone: NgZone,
private candidateService: CandidateService,
public dialog: MatDialog,
) { }
ngOnInit() {
this.getSchools();
this.getHireStages();
this.isPreviewOpen = false;
this.selectedTemplateName = null;
this.getAllTemplates();
}
triggerResize() {
this._ngZone.onStable.pipe(take(1)).subscribe(() => this.autosize.resizeToFitContent(true));
}
createNewTemp() {
this.router.navigate([`/create_template`])
}
// Send email template to multiple emails after search filter
sendEmail() {
this.dialog.open(DialogOverviewExampleDialog, {
width: '250px'
});
let candidateEmails = (<HTMLInputElement>document.getElementById("emailList")).value
let subject = this.sendForm.get('subjectForm').value
let body = "HARDCODED BODY"
this.candidateService.sendEmailWithoutPositions(candidateEmails, subject, body).subscribe(() => {
this.router.navigate(['/send_email']);
});
}
searchCandidates() {
this.emailSearchService.searchCandidates(this.searchForm.get('namesForm').value,
this.searchForm.get('majorsForm').value, this.schools.toString(),
this.hireStages.toString(), this.searchForm.get('startDateForm').value,
this.searchForm.get('endDateForm').value)
.subscribe(listOfEmails => {
console.log(listOfEmails);
(<HTMLInputElement>document.getElementById('emailList')).value = <string> listOfEmails;
})
}
//Send email to new candidate
sendEmail(candidateEmail: string, positionId: number[], subject: string, body: string) {
let details:emailDetails = new emailDetails();
details.to = candidateEmail;
details.positionId = positionId;
details.subject = subject;
details.body = body;
return this.http.post<emailDetails>(`${this.context.getOutgoingEmailUrl()}`, details)
}
// Send email to string of search/filtered candidate emails
sendEmailWithoutPositions(candidateEmails: string, subject: string, body: string) {
let details:emailDetails2 = new emailDetails2();
details.to = candidateEmails;
details.subject = subject;
details.body = body;
return this.http.post<emailDetails2>(`${this.context.getOutgoingEmailUrl()}`, details)
}
HTML
<mat-grid-tile colspan="6" rowspan="4">
<div class='search'>
<form [formGroup]='searchForm' autocomplete='off' novalidate>
<mat-form-field class="nameSearch">
<span matPrefix>Name: </span>
<input matInput id='namesForm' placeholder=" Enter candidate name" formControlName='namesForm'>
</mat-form-field>
<mat-form-field class="majorSearch">
<span matPrefix>Major: </span>
<input matInput id='majorsForm' placeholder=" Enter candidate major" formControlName="majorsForm">
</mat-form-field>
<tr>
<td>
<mat-form-field *ngIf="schoolSource" class="schools">
<mat-label>Schools</mat-label>
<mat-chip-list #chipList>
<mat-chip *ngFor="let school of schools" [selectable]="true" [removable]="true"
(removed)="removeSchool(school)">
{{ school }}
<mat-icon matChipRemove *ngIf="removable">cancel</mat-icon>
</mat-chip>
<input input='schoolsForm' placeholder="Choose school(s)" #schoolInput [formControl]="schoolCtrl"
[matAutocomplete]="auto" [matChipInputFor]="chipList"
[matChipInputSeparatorKeyCodes]="separatorKeysCodes"
[matChipInputAddOnBlur]="addOnBlur" formControlName='schoolsForm'>
</mat-chip-list>
<mat-autocomplete #auto (optionSelected)="selectedSchool($event)">
<mat-option *ngFor="let school of schoolSource" [value]='schoolId'>
{{ school.schoolName }}
</mat-option>
</mat-autocomplete>
</mat-form-field>
</td>
<td>
<mat-form-field *ngIf="hireStageSource" class="hireStages">
<mat-label>Hire Stage</mat-label>
<mat-chip-list #chipList1>
<mat-chip *ngFor="let hireStage of hireStages" [selectable]="true" [removable]="true"
(removed)="removeStage(hireStage)">
{{ hireStage }}
<mat-icon matChipRemove *ngIf="removable">cancel</mat-icon>
</mat-chip>
<input id='stagesForm' placeholder="Choose Hire Stage(s)" #hireStageInput [formControl]="hireStageCtrl"
[matAutocomplete]="auto1" [matChipInputFor]="chipList1"
[matChipInputSeparatorKeyCodes]="separatorKeysCodes"
[matChipInputAddOnBlur]="addOnBlur" formControlName='stagesForm'>
</mat-chip-list>
<mat-autocomplete #auto1 (optionSelected)="selectedStage($event)">
<mat-option *ngFor="let hireStage of hireStageSource" [value]='stageId'>
{{ hireStage.stageName }}
</mat-option>
</mat-autocomplete>
</mat-form-field>
<tr>
<div class="dates">
<mat-form-field class="startDate">
<input matInput id='startDateForm' [matDatepicker]="picker" placeholder="Start date"
name="startDate" formControlName='startDateForm'>
<mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle>
<mat-datepicker #picker></mat-datepicker>
</mat-form-field>
<mat-form-field class="endDate">
<input matInput id='endDateForm'[matDatepicker]="picker2" placeholder="End date"
name="endDate" formControlName='endDateForm'>
<mat-datepicker-toggle matSuffix [for]="picker2"></mat-datepicker-toggle>
<mat-datepicker #picker2></mat-datepicker>
</mat-form-field>
<button class="addEmail" mat-raised-button color = "primary" (click) = "searchCandidates()">Add</button>
</div>
</tr>
</td>
</form>
</div>
</mat-grid-tile>
<mat-grid-tile colspan="4" rowspan="4">
<div class='send'>
<form [formGroup]='sendForm' autocomplete='off' novalidate name="form">
<tr>
<button class="newTemplateButt" mat-raised-button color = "primary" (click) = "createNewTemp()">Create New Template</button>
</tr>
<tr>
<mat-form-field class="sendToList">
<mat-label>Candidate Emails will be listed here</mat-label>
<textarea id = 'emailList'
matInput
cdkTextareaAutosize
#autosize = "cdkTextareaAutosize"
cdkAutosizeMinRows = "1"
cdkAutosizeMaxRows = "8"></textarea>
</mat-form-field>
</tr>
<tr>
<mat-form-field class = "subjectLine">
<span matPrefix>Subject: </span>
<input matInput id='subjectLine' formControlName='subjectForm'>
</mat-form-field>
</tr>
<button mat-raised-button color = "primary" class = "sendEmail" (click) = "sendEmail()">Send Email</button>
</form>
</div>
</mat-grid-tile>
</mat-grid-list>
<div class="email-templates" [style.display]="isPreviewOpen ? 'grid' : 'flex'">
<app-email-templates-list [templates]="templateList" [selectedTemplate]="selectedTemplateName" (display)="displayPreviewHandler($event)"></app-email-templates-list>```
<app-email-templates-preview [previewStatus]="isPreviewOpen" [selectedTemplate]="selectedTemplateName"></app-email-templates-preview>
</div>
sendEmail() {
this.dialog.open(DialogOverviewExampleDialog, {
width: '250px'
});
let candidateEmails = (<HTMLInputElement>document.getElementById("emailList")).value
let subject = this.sendForm.get('subjectForm').value
console.log(this.selectedTemplateName)
this.templateService.getTemplate(this.selectedTemplateName).subscribe((templateData : any) => {
console.log(templateData.Body)
console.log(templateData.Body.data)
let body = importTemplate(templateData.Body.data).toString();
console.log(body)
this.candidateService.sendEmailWithoutPositions(candidateEmails, subject, body).subscribe(() => {
this.router.navigate(['/send_email']);
});
})
}
This is now sending the templates, but images are failing to display. Still looking into that issue.
Edit: The images weren't sending because they were base64 encoded. When viewing the source of all images in google images search results, they all showed base64 encoding. I noticed that when I went to the source of these images, it would give me a more specific src such as https://......jpg. When I dragged and dropped this source image into my template and saved and sent, it forwent the base64 encoding and therefore, images show up in my Gmail inbox when sent from my application now.
This is an angular app, In ref to my previous question question link. I add table rows on clicking button. In each table row I have mat-select element, on onclick event I call a function(onclickx).
html template
<td>
<div class="form-group">
<mat-form-field>
<mat-select (selectionChange) = "selectNumber($event.value)">
<mat-option *ngFor="let type of productNo" [value]=type.num >
{{type.num}}
</mat-option>
</mat-select>
</mat-form-field>
</div>
</td>
<tr *ngFor="let product of record.products; let i = index ">
<td>
<div class="form-group">
<mat-form-field>
<mat-select placeholder="Product" (click)="onclickx(i)">
<mat-optgroup *ngFor="let product of filteredProducts" [label]="product.daemon">
<mat-option *ngFor="let item of product.productlist" [value]="item.name">
{{item.name}}
</mat-option>
</mat-optgroup>
</mat-select>
</mat-form-field>
</div>
</td>
typescript
export class Template implements oninit{
filteredProducts:any[];
Value:number;
selectNumber (value) {
this.Value = value;
}
onclickx(i):any[]{
this.Value ? this.searchTerm =this.Value : this.searchTerm ="1";
this.filteredProducts[i] = this.searchTerm ? this.productlistArray.filter(productlistArray => productlistArray.number == this.searchTerm) : this.productlistArray;
return this.filteredProducts;
}
There will be two tables rows and each table row has this mat-select element,on clicking mat-select same function is called since "this.filteredProducts" is a global variable, when second row is updated with product list it affects the first row as well! how to overcome this problem.
We would like to consume child reactive form data from parent when we click on parent button. Currently we are using viewchild for getting the child cpomponent reference. We are getting all static data but not the form filled data.......................................................................................................
parent.component.ts
#ViewChild(DetailsComponent) childrenComponent: childrenComponent;
save(){
let model=this.childrenComponent.buildDetailsModel();
/*here api to save model*/
}
children.component.ts
buildDetailsModel(): Details {
var a = {
reportedToId: this.detailsForm.get('reportedTo').value,
reportedOn: this.detailsForm.get('reportedTime').value,
identifiedById: this.detailsForm.get('identifiedBy').value,
identifiedOn: this.detailsForm.get('dateAndTimeIdentified').value,
locationTypeId: this.detailsForm.get('locationType').value,
addressId: this.detailsForm.get('locationAddress').value,
AddressLine: this.detailsForm.get('locationOfAddress').value,
description: this.detailsForm.get('description').value,
PeopleExposed: this.dataSource
};
return a;
}
parent.html
<child></child>
child.html
<form [formGroup]="detailsForm">
<div fxLayout="column wrap" fxLayoutGap="12px">
<div fxLayout="column" fxLayout.lt-sm="column" fxLayout.lt-md="column"
fxLayoutGap="24px">
<div fxFlex="row" fxLayoutGap="24px" fxLayout.lt-md="column">
<div fxFlex="column">
<mat-form-field>
<mat-label>Reported To</mat-label>
<mat-select matInput formControlName="reportedTo">
<mat-option value="Test 1">Test 1</mat-option>
<mat-option value="Test 2">Test 1</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field>
<input matInput [matDatepicker]="reportedTime" placeholder="Date
and time reported" date="true" time="true"
formControlName="reportedTime">
<mat-datepicker-toggle matSuffix [for]="reportedTime"></mat-
datepicker-toggle>
<mat-datepicker #reportedTime></mat-datepicker>
</mat-form-field>
<mat-form-field>
<mat-label>Identified by</mat-label>
<mat-select matInput formControlName="identifiedBy">
<mat-option value="Test 1">Test 1</mat-option>
<mat-option value="Test 2">Test 1</mat-option>
</mat-select>
</mat-form-field>
</div>
Wrap your child form Inside form element so that you can submit your child form from parent, Then Inject FormGroupDirective in child component to get ref of parent form
<form (ngSubmit)="save()" [formGroup]="detailsForm">
<app-child></app-child>
<button type="button">Save</button>
</form>
Then use controlContainer to provide the existing FormGroupDirective in child component
childcomponent.ts
form;
constructor(private fb: FormBuilder, #Host() private parentFor: FormGroupDirective) { }
ngOnInit() {
this.form = this.parentFor.form;
//Add FormControl as per your need
this.form.addControl('child', this.fb.group({
name: "",
email: ""
}))
}
child.component.html
<form formGroupName="child">
<input formControlName="name">
<input formControlName="email">
</form>
Example:https://stackblitz.com/edit/angular-xusdev
If use a "referenceVariable" you has access to all the public variables and function of the "child"
<button (click)="click(mychild)"></button>
<child #mychild></child>
click(mychild.any)
{
console.log(mychild.detailsForm);
}
Anyway, I think you want a child that belong to a Form. For this you can use viewProviders in child
viewProviders: [
{
provide: ControlContainer,
useExisting: FormGroupDirective
}
]
As this link show
I have a very strange case: After setting up a component containing a form, interacting with the form is incredibly slow.
After a click on a dropdown, the form reacts only when the zone.js timeout occurs and the periodic change detection kicks in.
Any idea why this could be the case? Why would a component/form be outside of the zone.js change detection? I don't have any errors.
The only debugging input I have is, that on performance profiling in chrome devtools, I get the tap event and then 5-12seconds later, zone.js triggers the UI animation of showing the dropdown options.
In the Chrome DevTools Performance Profiler, this looks like this:
I tap the dropdown around 2 seconds after profiling:
And then 10 seconds later, zone.js, does a periodic update which triggers the dropdown:
Between, nothing happens.
I'm using NgRx and the switch to the component with the form happens in an #Effect, where I call the router.
The Effect looks like this:
(It wasn't working with RxJS5 either, so it shouldn't have anything to do with the migration)
#Effect()
placesDetails$ = this.actions$
.ofType<PlaceSelectedAction>(PLACE_SELECTED_ACTION)
.pipe(
switchMap((action: PlaceSelectedAction) =>
this.placesService.loadPlacesDetails(action.payload)
),
map(data => new PlaceDetailsLoadedAction(data)),
tap(_ => this.router.navigate(["/place-details"]))
);
The component itself looks like this:
import { Component } from "#angular/core";
import { Store } from "#ngrx/store";
import { ApplicationState } from "../store/application-state";
import { Router } from "#angular/router";
import { Card } from "../../../../shared/model/card";
#Component({
selector: "app-place-details",
templateUrl: "./place-details.component.html",
styleUrls: ["./place-details.component.scss"]
})
export class PlaceDetailsComponent {
card: Card;
constructor(private store: Store<ApplicationState>, private router: Router) {
this.store.subscribe(state => (this.card = state.cardDataState.card));
}
travelTypeLocation = [
{ value: "city", viewValue: "City" },
{ value: "beach", viewValue: "Beach" },
{ value: "mountains", viewValue: "Mountains" },
{ value: "countryside", viewValue: "Countryside" }
];
travelTypeActivity = [
{ value: "relax", viewValue: "Relax" },
{ value: "sports", viewValue: "Sports" },
{ value: "culture", viewValue: "Culture" },
{ value: "party", viewValue: "Party" }
];
travelTypeCompanions = [
{ value: "family", viewValue: "Family" },
{ value: "partner", viewValue: "Partner" },
{ value: "single", viewValue: "Single" },
{ value: "friends", viewValue: "Friends" },
{ value: "colleagues", viewValue: "Colleagues" }
];
checkPlaceDetails() {
//this.store.dispatch(new PlaceDetailsSubmitAction());
}
goBack() {
this.router.navigate(["/search-places"]);
}
}
And this is the HTML:
<div class="container" fxLayout.xs="column">
<h3>Fill out Place Details</h3>
<form>
<mat-form-field class="full-width">
<input
matInput
placeholder="Title"
type="text"
required
name="title"
[(ngModel)]="card.title">
<mat-error *ngIf="card.title">{{ card.title }}</mat-error>
</mat-form-field>
<mat-form-field class="full-width">
<input
matInput
placeholder="Description"
type="text"
name="description"
required
[(ngModel)]="card.description"
/>
</mat-form-field>
<mat-form-field class="full-width">
<mat-select
placeholder="Travel Type Location"
name="travelTypeLocation"
required
[(ngModel)]="card.travelTypeLocation"
>
<mat-option *ngFor="let type of travelTypeLocation" [value]="type.value">
{{ type.viewValue }}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field class="full-width">
<input
matInput
placeholder="Travel Dimension Location (e.g. surfing, biking, museum, theater)"
type="text"
name="travelDimensionLocation"
required
[(ngModel)]="card.travelDimensionLocation"
/>
</mat-form-field>
<mat-form-field class="full-width">
<mat-select
placeholder="Travel Type Activity"
name="travelTypeActivity"
required
[(ngModel)]="card.travelTypeActivity"
>
<mat-option *ngFor="let type of travelTypeActivity" [value]="type.value">
{{ type.viewValue }}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field class="full-width">
<input
matInput
placeholder="Travel Dimension Activity (e.g. modern city, historic city, hills, high mountains)"
type="text"
name="travelDimensionActivity"
required
[(ngModel)]="card.travelDimensionActivity"
/>
</mat-form-field>
<mat-form-field class="full-width">
<mat-select
placeholder="Travel Companions"
name="travelTypeCompanions"
required
[(ngModel)]="card.travelTypeCompanions"
>
<mat-option *ngFor="let type of travelTypeCompanions" [value]="type.value">
{{ type.viewValue }}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field class="full-width">
<input
matInput
placeholder="Duration"
type="text"
required
name="duration"
[(ngModel)]="card.averageDuration"
/>
</mat-form-field>
<mat-form-field class="full-width">
<input
matInput
required
placeholder="Cost (€)"
type="number"
name="cost"
[(ngModel)]="card.cost"
/>
</mat-form-field>
<button mat-raised-button color="primary" (click)="checkPlaceDetails()">Add Card</button>
<button mat-raised-button color="secondary" (click)="goBack()">Go Back</button>
</form>
</div>
Please let me know what could be of importance? I'm lost.
Thanks!
This one was hard to figure out. But apparently there was a bug with zone.js and RxJS.
After including the import 'zone.js/dist/zone-patch-rxjs'; in polyfills it now works as expected with no delay after form interaction.