diff --git a/src/main/webapp/app/lecture/lecture-unit/lecture-unit-management/video-unit-form/video-unit-form.component.html b/src/main/webapp/app/lecture/lecture-unit/lecture-unit-management/video-unit-form/video-unit-form.component.html index 28218967e14e..8a2515c4a08d 100644 --- a/src/main/webapp/app/lecture/lecture-unit/lecture-unit-management/video-unit-form/video-unit-form.component.html +++ b/src/main/webapp/app/lecture/lecture-unit/lecture-unit-management/video-unit-form/video-unit-form.component.html @@ -107,10 +107,10 @@
- - @if (hasCancelButton) { + @if (hasCancelButton()) { diff --git a/src/main/webapp/app/lecture/lecture-unit/lecture-unit-management/video-unit-form/video-unit-form.component.ts b/src/main/webapp/app/lecture/lecture-unit/lecture-unit-management/video-unit-form/video-unit-form.component.ts index 65ca7da964f2..543526c9491b 100644 --- a/src/main/webapp/app/lecture/lecture-unit/lecture-unit-management/video-unit-form/video-unit-form.component.ts +++ b/src/main/webapp/app/lecture/lecture-unit/lecture-unit-management/video-unit-form/video-unit-form.component.ts @@ -1,9 +1,10 @@ import dayjs from 'dayjs/esm'; -import { Component, EventEmitter, Input, OnChanges, OnInit, Output } from '@angular/core'; +import { Component, computed, effect, inject, input, output, untracked } from '@angular/core'; import { AbstractControl, FormBuilder, FormGroup, ValidationErrors, Validators } from '@angular/forms'; import urlParser from 'js-video-url-parser'; import { faArrowLeft, faTimes } from '@fortawesome/free-solid-svg-icons'; import { CompetencyLectureUnitLink } from 'app/entities/competency.model'; +import { toSignal } from '@angular/core/rxjs-interop'; export interface VideoUnitFormData { name?: string; @@ -57,30 +58,41 @@ function videoSourceUrlValidator(control: AbstractControl): ValidationErrors | u selector: 'jhi-video-unit-form', templateUrl: './video-unit-form.component.html', }) -export class VideoUnitFormComponent implements OnInit, OnChanges { - @Input() - formData: VideoUnitFormData; - @Input() - isEditMode = false; +export class VideoUnitFormComponent { + protected readonly faTimes = faTimes; + protected readonly faArrowLeft = faArrowLeft; - @Output() - formSubmitted: EventEmitter = new EventEmitter(); - form: FormGroup; + private readonly formBuilder = inject(FormBuilder); - @Input() - hasCancelButton: boolean; - @Output() - onCancel: EventEmitter = new EventEmitter(); + formData = input(); + isEditMode = input(false); - faTimes = faTimes; + formSubmitted = output(); + + hasCancelButton = input(); + onCancel = output(); videoSourceUrlValidator = videoSourceUrlValidator; videoSourceTransformUrlValidator = videoSourceTransformUrlValidator; - // Icons - faArrowLeft = faArrowLeft; - - constructor(private fb: FormBuilder) {} + form: FormGroup = this.formBuilder.group({ + name: [undefined as string | undefined, [Validators.required, Validators.maxLength(255)]], + description: [undefined as string | undefined, [Validators.maxLength(1000)]], + releaseDate: [undefined as dayjs.Dayjs | undefined], + source: [undefined as string | undefined, [Validators.required, this.videoSourceUrlValidator]], + urlHelper: [undefined as string | undefined, this.videoSourceTransformUrlValidator], + competencyLinks: [undefined as CompetencyLectureUnitLink[] | undefined], + }); + private readonly statusChanges = toSignal(this.form.statusChanges ?? 'INVALID'); + isFormValid = computed(() => this.statusChanges() === 'VALID'); + + constructor() { + effect(() => { + if (this.isEditMode() && this.formData()) { + untracked(() => this.setFormValues(this.formData()!)); + } + }); + } get nameControl() { return this.form.get('name'); @@ -102,31 +114,6 @@ export class VideoUnitFormComponent implements OnInit, OnChanges { return this.form.get('urlHelper'); } - ngOnChanges(): void { - this.initializeForm(); - if (this.isEditMode && this.formData) { - this.setFormValues(this.formData); - } - } - - ngOnInit(): void { - this.initializeForm(); - } - - private initializeForm() { - if (this.form) { - return; - } - this.form = this.fb.group({ - name: [undefined as string | undefined, [Validators.required, Validators.maxLength(255)]], - description: [undefined as string | undefined, [Validators.maxLength(1000)]], - releaseDate: [undefined as dayjs.Dayjs | undefined], - source: [undefined as string | undefined, [Validators.required, this.videoSourceUrlValidator]], - urlHelper: [undefined as string | undefined, this.videoSourceTransformUrlValidator], - competencyLinks: [undefined as CompetencyLectureUnitLink[] | undefined], - }); - } - private setFormValues(formData: VideoUnitFormData) { this.form.patchValue(formData); } @@ -136,10 +123,6 @@ export class VideoUnitFormComponent implements OnInit, OnChanges { this.formSubmitted.emit(videoUnitFormData); } - get isSubmitPossible() { - return !this.form.invalid; - } - get isTransformable() { if (this.urlHelperControl!.value === undefined || this.urlHelperControl!.value === null || this.urlHelperControl!.value === '') { return false; diff --git a/src/test/javascript/spec/component/lecture-unit/video-unit/video-unit-form.component.spec.ts b/src/test/javascript/spec/component/lecture-unit/video-unit/video-unit-form.component.spec.ts index bf48893cf982..445163b967ff 100644 --- a/src/test/javascript/spec/component/lecture-unit/video-unit/video-unit-form.component.spec.ts +++ b/src/test/javascript/spec/component/lecture-unit/video-unit/video-unit-form.component.spec.ts @@ -7,6 +7,7 @@ import { MockComponent, MockPipe } from 'ng-mocks'; import { FormDateTimePickerComponent } from 'app/shared/date-time-picker/date-time-picker.component'; import { FaIconComponent } from '@fortawesome/angular-fontawesome'; import { CompetencySelectionComponent } from 'app/shared/competency-selection/competency-selection.component'; + describe('VideoUnitFormComponent', () => { const validYouTubeUrl = 'https://www.youtube.com/watch?v=8iU8LPEa4o0'; const validYouTubeUrlInEmbeddableFormat = 'https://www.youtube.com/embed/8iU8LPEa4o0'; @@ -161,7 +162,7 @@ describe('VideoUnitFormComponent', () => { }); it('should correctly set form values in edit mode', () => { - videoUnitFormComponent.isEditMode = true; + videoUnitFormComponentFixture.componentRef.setInput('isEditMode', true); const formData: VideoUnitFormData = { name: 'test', description: 'lorem ipsum', @@ -170,12 +171,18 @@ describe('VideoUnitFormComponent', () => { }; videoUnitFormComponentFixture.detectChanges(); - videoUnitFormComponent.formData = formData; - videoUnitFormComponent.ngOnChanges(); + videoUnitFormComponentFixture.componentRef.setInput('formData', formData); + videoUnitFormComponentFixture.detectChanges(); expect(videoUnitFormComponent.nameControl?.value).toEqual(formData.name); expect(videoUnitFormComponent.releaseDateControl?.value).toEqual(formData.releaseDate); expect(videoUnitFormComponent.descriptionControl?.value).toEqual(formData.description); expect(videoUnitFormComponent.sourceControl?.value).toEqual(formData.source); }); + + it('should emit onCancel event when cancelForm is called', () => { + const onCancelSpy = jest.spyOn(videoUnitFormComponent.onCancel, 'emit'); + videoUnitFormComponent.cancelForm(); + expect(onCancelSpy).toHaveBeenCalled(); + }); });