I'm trying to create my own todo form and it came dowm to validating input of single todo item. Somehow validation doesn't work correctly, it works only if I focus the input, click outside of it, then foucs it once again and then click outside once again. Can somebody, please, explain, me what I'm missing here? I know it's possible to rewrite the code, but would be grateful to understand the reason of such behaviour.
By commenting out different parts of code, I've reached out that if I delete (updateTodoChildEvent)="updateTodo($event)" from todo-item.component.html validation works correctly, but I don't know why.
todo-item.component.ts
import {Component, ElementRef, EventEmitter, Input, OnInit, Output} from '@angular/core';
import {FormControl, FormGroup, Validators, FormBuilder} from "@angular/forms";
import {Todo} from "../todo";
import {TodoService} from "../todo.service";
@Component({
selector: 'app-todo-item',
templateUrl: './todo-item.component.html',
styleUrls: ['./todo-item.component.css']
})
export class TodoItemComponent {
@Input() todoItemsList: Todo[] = [];
@Input() todoItem!: Todo;
@Output() updateTodoEvent = new EventEmitter<Todo>();
constructor(private todoService: TodoService) {
}
updateTodo(todo: Todo) {
this.updateTodoEvent.emit(todo);
}
}
todo-item.component.html
<div>
<form>
<app-todo-edit
[todoItemChild]="todoItem"
(updateTodoChildEvent)="updateTodo($event)"
>
</app-todo-edit>
</form>
</div>
todo-edit.component.ts
import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core';
import {Todo} from "../todo";
import {FormControl, FormGroup, Validators} from "@angular/forms";
@Component({
selector: 'app-todo-edit',
templateUrl: './todo-edit.component.html',
styleUrls: ['./todo-edit.component.css']
})
export class TodoEditComponent implements OnInit {
@Output() updateTodoChildEvent = new EventEmitter();
@Input() todoItemChild!: Todo;
formControlChild = new FormControl('', [Validators.required, Validators.minLength(3)])
ngOnInit() {
this.formControlChild.setValue(this.todoItemChild.name);
}
onChildInputChange(todo: Todo, val: string) {
this.updateTodoChildEvent.emit({id: todo.id, name: val});
}
getErrorMessage() {
if (this.formControlChild.hasError('required')) {
return 'You must enter a value';
}
return this.formControlChild.hasError('minlength') ? 'Too short, should be at least 3 symbols' : '';
}
}
todo-edit.component.html
<form>
<mat-form-field>
<mat-label>Edit Todo</mat-label>
<input
matInput
type="text"
#inputRef
(change)="onChildInputChange(todoItemChild, inputRef.value)"
[formControl]="formControlChild"
>
<mat-error *ngIf="formControlChild.invalid">{{getErrorMessage()}}</mat-error>
</mat-form-field>
</form>
