MOBILE-3947 form: Add types to FormControl
parent
350f5792ca
commit
27b980d710
|
@ -39,10 +39,10 @@ import { CoreLogger } from '@singletons/logger';
|
|||
})
|
||||
export class AddonBlockTimelineComponent implements OnInit, ICoreBlockComponent {
|
||||
|
||||
sort = new FormControl();
|
||||
sort = new FormControl(AddonBlockTimelineSort.ByDates);
|
||||
sort$!: Observable<AddonBlockTimelineSort>;
|
||||
sortOptions!: AddonBlockTimelineOption<AddonBlockTimelineSort>[];
|
||||
filter = new FormControl();
|
||||
filter = new FormControl(AddonBlockTimelineFilter.Next30Days);
|
||||
filter$!: Observable<AddonBlockTimelineFilter>;
|
||||
statusFilterOptions!: AddonBlockTimelineOption<AddonBlockTimelineFilter>[];
|
||||
dateFilterOptions!: AddonBlockTimelineOption<AddonBlockTimelineFilter>[];
|
||||
|
|
|
@ -78,9 +78,9 @@ export class AddonCalendarEditEventPage implements OnInit, OnDestroy, CanLeave {
|
|||
|
||||
// Form variables.
|
||||
form: FormGroup;
|
||||
typeControl: FormControl;
|
||||
groupControl: FormControl;
|
||||
descriptionControl: FormControl;
|
||||
typeControl: FormControl<AddonCalendarEventType | null>;
|
||||
groupControl: FormControl<number | null>;
|
||||
descriptionControl: FormControl<string>;
|
||||
|
||||
// Reminders.
|
||||
remindersEnabled = false;
|
||||
|
@ -103,9 +103,9 @@ export class AddonCalendarEditEventPage implements OnInit, OnDestroy, CanLeave {
|
|||
this.form = new FormGroup({});
|
||||
|
||||
// Initialize form variables.
|
||||
this.typeControl = this.fb.control('', Validators.required);
|
||||
this.groupControl = this.fb.control('');
|
||||
this.descriptionControl = this.fb.control('');
|
||||
this.typeControl = this.fb.control(null, Validators.required);
|
||||
this.groupControl = this.fb.control(null);
|
||||
this.descriptionControl = this.fb.control('', { nonNullable: true });
|
||||
this.form.addControl('name', this.fb.control('', Validators.required));
|
||||
this.form.addControl('eventtype', this.typeControl);
|
||||
this.form.addControl('categoryid', this.fb.control(''));
|
||||
|
@ -322,11 +322,11 @@ export class AddonCalendarEditEventPage implements OnInit, OnDestroy, CanLeave {
|
|||
|
||||
this.form.controls.name.setValue(event.name);
|
||||
this.form.controls.timestart.setValue(CoreTimeUtils.toDatetimeFormat(event.timestart * 1000));
|
||||
this.form.controls.eventtype.setValue(event.eventtype);
|
||||
this.typeControl.setValue(event.eventtype as AddonCalendarEventType);
|
||||
this.form.controls.categoryid.setValue(event.categoryid || '');
|
||||
this.form.controls.courseid.setValue(courseId || '');
|
||||
this.form.controls.groupcourseid.setValue(courseId || '');
|
||||
this.form.controls.groupid.setValue(event.groupid || '');
|
||||
this.groupControl.setValue(event.groupid || null);
|
||||
this.form.controls.description.setValue(event.description);
|
||||
this.form.controls.location.setValue(event.location);
|
||||
|
||||
|
@ -410,7 +410,7 @@ export class AddonCalendarEditEventPage implements OnInit, OnDestroy, CanLeave {
|
|||
try {
|
||||
await this.loadGroups(courseId);
|
||||
|
||||
this.groupControl.setValue('');
|
||||
this.groupControl.setValue(null);
|
||||
} catch (error) {
|
||||
CoreDomUtils.showErrorModalDefault(error, 'Error getting data.');
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ import { AddonModAssignFeedbackPluginBaseComponent } from '@addons/mod/assign/cl
|
|||
})
|
||||
export class AddonModAssignFeedbackCommentsComponent extends AddonModAssignFeedbackPluginBaseComponent implements OnInit {
|
||||
|
||||
control?: FormControl;
|
||||
control?: FormControl<string>;
|
||||
component = AddonModAssignProvider.COMPONENT;
|
||||
text = '';
|
||||
isSent = false;
|
||||
|
@ -76,7 +76,7 @@ export class AddonModAssignFeedbackCommentsComponent extends AddonModAssignFeedb
|
|||
}
|
||||
});
|
||||
} else if (this.edit) {
|
||||
this.control = this.fb.control(this.text);
|
||||
this.control = this.fb.control(this.text, { nonNullable: true });
|
||||
}
|
||||
} finally {
|
||||
this.loaded = true;
|
||||
|
|
|
@ -31,7 +31,7 @@ import { AddonModAssignSubmissionOnlineTextPluginData } from '../services/handle
|
|||
})
|
||||
export class AddonModAssignSubmissionOnlineTextComponent extends AddonModAssignSubmissionPluginBaseComponent implements OnInit {
|
||||
|
||||
control?: FormControl;
|
||||
control?: FormControl<string>;
|
||||
words = 0;
|
||||
component = AddonModAssignProvider.COMPONENT;
|
||||
text = '';
|
||||
|
@ -94,7 +94,7 @@ export class AddonModAssignSubmissionOnlineTextComponent extends AddonModAssignS
|
|||
});
|
||||
} else {
|
||||
// Create and add the control.
|
||||
this.control = this.fb.control(this.text);
|
||||
this.control = this.fb.control(this.text, { nonNullable: true });
|
||||
}
|
||||
|
||||
// Calculate initial words.
|
||||
|
|
|
@ -83,7 +83,7 @@ export class AddonModForumPostComponent implements OnInit, OnDestroy, OnChanges
|
|||
|
||||
@ViewChild('replyFormEl') formElement!: ElementRef;
|
||||
|
||||
messageControl = new FormControl();
|
||||
messageControl = new FormControl<string | null>(null);
|
||||
|
||||
uniqueId!: string;
|
||||
defaultReplySubject!: string;
|
||||
|
|
|
@ -70,7 +70,7 @@ export class AddonModForumNewDiscussionPage implements OnInit, OnDestroy, CanLea
|
|||
@ViewChild(CoreEditorRichTextEditorComponent) messageEditor!: CoreEditorRichTextEditorComponent;
|
||||
|
||||
component = AddonModForumProvider.COMPONENT;
|
||||
messageControl = new FormControl();
|
||||
messageControl = new FormControl<string | null>(null);
|
||||
groupsLoaded = false;
|
||||
showGroups = false;
|
||||
hasOffline = false;
|
||||
|
|
|
@ -58,7 +58,7 @@ export class AddonModGlossaryEditPage implements OnInit, CanLeave {
|
|||
courseId!: number;
|
||||
loaded = false;
|
||||
glossary?: AddonModGlossaryGlossary;
|
||||
definitionControl = new FormControl();
|
||||
definitionControl = new FormControl<string | null>(null);
|
||||
categories: AddonModGlossaryCategory[] = [];
|
||||
showAliases = true;
|
||||
editorExtraParams: Record<string, unknown> = {};
|
||||
|
|
|
@ -369,7 +369,7 @@ export class AddonModLessonHelperProvider {
|
|||
};
|
||||
|
||||
// Init the control.
|
||||
essayQuestion.control = this.formBuilder.control('');
|
||||
essayQuestion.control = this.formBuilder.control('', { nonNullable: true });
|
||||
questionForm.addControl(essayQuestion.textarea.name, essayQuestion.control);
|
||||
}
|
||||
|
||||
|
@ -635,7 +635,7 @@ export type AddonModLessonInputQuestion = AddonModLessonQuestionBasicData & {
|
|||
export type AddonModLessonEssayQuestion = AddonModLessonQuestionBasicData & {
|
||||
useranswer?: string; // User answer, for reviewing.
|
||||
textarea?: AddonModLessonTextareaData; // Data for the textarea.
|
||||
control?: FormControl; // Form control.
|
||||
control?: FormControl<string>; // Form control.
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -47,7 +47,7 @@ export class AddonModWikiEditPage implements OnInit, OnDestroy, CanLeave {
|
|||
courseId?: number; // Course the wiki belongs to.
|
||||
title?: string; // Title to display.
|
||||
pageForm: FormGroup; // The form group.
|
||||
contentControl: FormControl; // The FormControl for the page content.
|
||||
contentControl: FormControl<string>; // The FormControl for the page content.
|
||||
canEditTitle = false; // Whether title can be edited.
|
||||
loaded = false; // Whether the data has been loaded.
|
||||
component = AddonModWikiProvider.COMPONENT; // Component to link the files to.
|
||||
|
@ -74,7 +74,7 @@ export class AddonModWikiEditPage implements OnInit, OnDestroy, CanLeave {
|
|||
constructor(
|
||||
protected formBuilder: FormBuilder,
|
||||
) {
|
||||
this.contentControl = this.formBuilder.control('');
|
||||
this.contentControl = this.formBuilder.control('', { nonNullable: true });
|
||||
this.pageForm = this.formBuilder.group({});
|
||||
}
|
||||
|
||||
|
|
|
@ -73,7 +73,7 @@ export class AddonModWorkshopAssessmentStrategyComponent implements OnInit, OnDe
|
|||
assessmentStrategyLoaded = false;
|
||||
notSupported = false;
|
||||
feedbackText = '';
|
||||
feedbackControl = new FormControl();
|
||||
feedbackControl = new FormControl<string | null>(null);
|
||||
overallFeedkback = false;
|
||||
overallFeedkbackRequired = false;
|
||||
component = ADDON_MOD_WORKSHOP_COMPONENT;
|
||||
|
|
|
@ -32,7 +32,7 @@ import { CoreFileEntry } from '@services/file-helper';
|
|||
})
|
||||
export class AddonQtypeEssayComponent extends CoreQuestionBaseComponent<AddonModQuizEssayQuestion> {
|
||||
|
||||
formControl?: FormControl;
|
||||
formControl?: FormControl<string | null>;
|
||||
attachments?: CoreFileEntry[];
|
||||
uploadFilesSupported = false;
|
||||
|
||||
|
@ -52,7 +52,7 @@ export class AddonQtypeEssayComponent extends CoreQuestionBaseComponent<AddonMod
|
|||
|
||||
this.initEssayComponent(this.review);
|
||||
|
||||
this.formControl = this.fb.control(this.question?.textarea?.text);
|
||||
this.formControl = this.fb.control(this.question?.textarea?.text ?? null);
|
||||
|
||||
if (this.question?.allowsAttachments && this.uploadFilesSupported && !this.review) {
|
||||
this.loadAttachments();
|
||||
|
|
|
@ -27,20 +27,23 @@ import { CoreUtils } from '@services/utils/utils';
|
|||
templateUrl: 'addon-user-profile-field-checkbox.html',
|
||||
styleUrls: ['./checkbox.scss'],
|
||||
})
|
||||
export class AddonUserProfileFieldCheckboxComponent extends CoreUserProfileFieldBaseComponent {
|
||||
export class AddonUserProfileFieldCheckboxComponent extends CoreUserProfileFieldBaseComponent<boolean> {
|
||||
|
||||
/**
|
||||
* Create the Form control.
|
||||
*
|
||||
* @returns Form control.
|
||||
*/
|
||||
protected createFormControl(field: AuthEmailSignupProfileField): FormControl {
|
||||
protected createFormControl(field: AuthEmailSignupProfileField): FormControl<boolean> {
|
||||
const formData = {
|
||||
value: CoreUtils.isTrueOrOne(field.defaultdata),
|
||||
disabled: this.disabled,
|
||||
};
|
||||
|
||||
return new FormControl(formData, this.required && !field.locked ? Validators.requiredTrue : null);
|
||||
return new FormControl(formData, {
|
||||
validators: this.required && !field.locked ? Validators.requiredTrue : null,
|
||||
nonNullable: true,
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ import { CoreUserProfileFieldBaseComponent } from '@features/user/classes/base-p
|
|||
selector: 'addon-user-profile-field-datetime',
|
||||
templateUrl: 'addon-user-profile-field-datetime.html',
|
||||
})
|
||||
export class AddonUserProfileFieldDatetimeComponent extends CoreUserProfileFieldBaseComponent {
|
||||
export class AddonUserProfileFieldDatetimeComponent extends CoreUserProfileFieldBaseComponent<string | undefined> {
|
||||
|
||||
ionDateTimePresentation = 'date';
|
||||
min?: string;
|
||||
|
@ -84,13 +84,16 @@ export class AddonUserProfileFieldDatetimeComponent extends CoreUserProfileField
|
|||
*
|
||||
* @returns Form control.
|
||||
*/
|
||||
protected createFormControl(field: AuthEmailSignupProfileField): FormControl {
|
||||
protected createFormControl(field: AuthEmailSignupProfileField): FormControl<string | undefined> {
|
||||
const formData = {
|
||||
value: field.defaultdata != '0' ? field.defaultdata : undefined,
|
||||
disabled: this.disabled,
|
||||
};
|
||||
|
||||
return new FormControl(formData, this.required && !field.locked ? Validators.required : null);
|
||||
return new FormControl(formData, {
|
||||
validators: this.required && !field.locked ? Validators.required : null,
|
||||
nonNullable: true,
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -40,7 +40,7 @@ import { FormControl } from '@angular/forms';
|
|||
})
|
||||
export class CoreInputErrorsComponent implements OnInit, OnChanges {
|
||||
|
||||
@Input() control?: FormControl; // Needed to be able to check the validity of the input.
|
||||
@Input() control?: FormControl<unknown>; // Needed to be able to check the validity of the input.
|
||||
@Input() errorMessages: Record<string, string> = {}; // Error messages to show. Keys must be the name of the error.
|
||||
@Input() errorText = ''; // Set other non automatic errors.
|
||||
errorKeys: string[] = [];
|
||||
|
|
|
@ -66,7 +66,7 @@ export class CoreEditorRichTextEditorComponent implements OnInit, AfterViewInit,
|
|||
// @todo Implement ControlValueAccessor https://angular.io/api/forms/ControlValueAccessor.
|
||||
|
||||
@Input() placeholder = ''; // Placeholder to set in textarea.
|
||||
@Input() control?: FormControl; // Form control.
|
||||
@Input() control?: FormControl<string | undefined | null>; // Form control.
|
||||
@Input() name = 'core-rich-text-editor'; // Name to set to the textarea.
|
||||
@Input() component?: string; // The component to link the files to.
|
||||
@Input() componentId?: number; // An ID to use in conjunction with the component.
|
||||
|
@ -75,7 +75,7 @@ export class CoreEditorRichTextEditorComponent implements OnInit, AfterViewInit,
|
|||
@Input() contextInstanceId?: number; // The instance ID related to the context.
|
||||
@Input() elementId?: string; // An ID to set to the element.
|
||||
@Input() draftExtraParams?: Record<string, unknown>; // Extra params to identify the draft.
|
||||
@Output() contentChanged: EventEmitter<string>;
|
||||
@Output() contentChanged: EventEmitter<string | undefined | null>;
|
||||
|
||||
@ViewChild('editor') editor?: ElementRef; // WYSIWYG editor.
|
||||
@ViewChild('textarea') textarea?: IonTextarea; // Textarea editor.
|
||||
|
@ -190,8 +190,8 @@ export class CoreEditorRichTextEditorComponent implements OnInit, AfterViewInit,
|
|||
// Setup the editor.
|
||||
this.editorElement = this.editor?.nativeElement as HTMLDivElement;
|
||||
this.setContent(this.control?.value);
|
||||
this.originalContent = this.control?.value;
|
||||
this.lastDraft = this.control?.value;
|
||||
this.originalContent = this.control?.value ?? undefined;
|
||||
this.lastDraft = this.control?.value ?? '';
|
||||
|
||||
// Use paragraph on enter.
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
|
@ -261,19 +261,19 @@ export class CoreEditorRichTextEditorComponent implements OnInit, AfterViewInit,
|
|||
|
||||
// Apply the new content.
|
||||
this.setContent(newValue);
|
||||
this.originalContent = newValue;
|
||||
this.originalContent = newValue ?? undefined;
|
||||
this.infoMessage = undefined;
|
||||
|
||||
// Save a draft so the original content is saved.
|
||||
this.lastDraft = newValue;
|
||||
this.lastDraft = newValue ?? '';
|
||||
CoreEditorOffline.saveDraft(
|
||||
this.contextLevel || '',
|
||||
this.contextInstanceId || 0,
|
||||
this.elementId || '',
|
||||
this.draftExtraParams || {},
|
||||
this.pageInstance,
|
||||
newValue,
|
||||
newValue,
|
||||
this.lastDraft,
|
||||
this.originalContent,
|
||||
);
|
||||
});
|
||||
|
||||
|
@ -579,7 +579,7 @@ export class CoreEditorRichTextEditorComponent implements OnInit, AfterViewInit,
|
|||
* @param value text
|
||||
* @returns If value is null only a white space.
|
||||
*/
|
||||
protected isNullOrWhiteSpace(value: string | null): boolean {
|
||||
protected isNullOrWhiteSpace(value: string | null | undefined): boolean {
|
||||
if (value == null || value === undefined) {
|
||||
return true;
|
||||
}
|
||||
|
@ -595,7 +595,7 @@ export class CoreEditorRichTextEditorComponent implements OnInit, AfterViewInit,
|
|||
*
|
||||
* @param value New content.
|
||||
*/
|
||||
protected setContent(value: string | null): void {
|
||||
protected setContent(value: string | null | undefined): void {
|
||||
if (!this.editorElement || !this.textarea) {
|
||||
return;
|
||||
}
|
||||
|
@ -974,7 +974,7 @@ export class CoreEditorRichTextEditorComponent implements OnInit, AfterViewInit,
|
|||
return;
|
||||
}
|
||||
|
||||
const newText = this.control.value;
|
||||
const newText = this.control.value ?? '';
|
||||
|
||||
if (this.lastDraft == newText) {
|
||||
// Text hasn't changed, nothing to save.
|
||||
|
|
|
@ -69,8 +69,8 @@ export class CoreLoginEmailSignupPage implements OnInit {
|
|||
|
||||
// Data for age verification.
|
||||
ageVerificationForm: FormGroup;
|
||||
countryControl: FormControl;
|
||||
signUpCountryControl?: FormControl;
|
||||
countryControl: FormControl<string>;
|
||||
signUpCountryControl?: FormControl<string>;
|
||||
isMinor = false; // Whether the user is minor age.
|
||||
ageDigitalConsentVerification?: boolean; // Whether the age verification is enabled.
|
||||
supportName?: string;
|
||||
|
@ -93,7 +93,7 @@ export class CoreLoginEmailSignupPage implements OnInit {
|
|||
this.ageVerificationForm = this.fb.group({
|
||||
age: ['', Validators.required],
|
||||
});
|
||||
this.countryControl = this.fb.control('', Validators.required);
|
||||
this.countryControl = this.fb.control('', { validators: Validators.required, nonNullable: true });
|
||||
this.ageVerificationForm.addControl('country', this.countryControl);
|
||||
|
||||
// Create the signupForm with the basic controls. More controls will be added later.
|
||||
|
@ -141,7 +141,7 @@ export class CoreLoginEmailSignupPage implements OnInit {
|
|||
*/
|
||||
protected completeFormGroup(): void {
|
||||
this.signupForm.addControl('city', this.fb.control(this.settings?.defaultcity || ''));
|
||||
this.signUpCountryControl = this.fb.control(this.settings?.country || '');
|
||||
this.signUpCountryControl = this.fb.control(this.settings?.country || '', { nonNullable: true });
|
||||
this.signupForm.addControl('country', this.signUpCountryControl);
|
||||
|
||||
// Add the name fields.
|
||||
|
|
|
@ -24,7 +24,7 @@ import { CoreUserProfileField } from '@features/user/services/user';
|
|||
@Component({
|
||||
template: '',
|
||||
})
|
||||
export abstract class CoreUserProfileFieldBaseComponent implements OnInit {
|
||||
export abstract class CoreUserProfileFieldBaseComponent<T = string> implements OnInit {
|
||||
|
||||
@Input() field?: AuthEmailSignupProfileField | CoreUserProfileField; // The profile field to be rendered.
|
||||
@Input() signup = false; // True if editing the field in signup. Defaults to false.
|
||||
|
@ -36,7 +36,7 @@ export abstract class CoreUserProfileFieldBaseComponent implements OnInit {
|
|||
@Input() contextInstanceId?: number; // The instance ID related to the context.
|
||||
@Input() courseId?: number; // Course ID the field belongs to (if any). It can be used to improve performance with filters.
|
||||
|
||||
control?: FormControl;
|
||||
control?: FormControl<T>;
|
||||
modelName = '';
|
||||
value?: string;
|
||||
required?: boolean;
|
||||
|
@ -91,13 +91,16 @@ export abstract class CoreUserProfileFieldBaseComponent implements OnInit {
|
|||
*
|
||||
* @returns Form control.
|
||||
*/
|
||||
protected createFormControl(field: AuthEmailSignupProfileField): FormControl {
|
||||
protected createFormControl(field: AuthEmailSignupProfileField): FormControl<T> {
|
||||
const formData = {
|
||||
value: field.defaultdata,
|
||||
value: (field.defaultdata ?? '') as T,
|
||||
disabled: this.disabled,
|
||||
};
|
||||
|
||||
return new FormControl(formData, this.required && !field.locked ? Validators.required : null);
|
||||
return new FormControl(formData, {
|
||||
validators: this.required && !field.locked ? Validators.required : null,
|
||||
nonNullable: true,
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -22,10 +22,10 @@ import { catchError, filter } from 'rxjs/operators';
|
|||
* @param control Form control.
|
||||
* @returns Form control value observable.
|
||||
*/
|
||||
export function formControlValue<T = unknown>(control: FormControl): Observable<T> {
|
||||
export function formControlValue<T = unknown>(control: FormControl<T | null>): Observable<T> {
|
||||
return control.valueChanges.pipe(
|
||||
startWithOnSubscribed(() => control.value),
|
||||
filter(value => value !== null),
|
||||
filter((value): value is T => value !== null),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue