- {{errorMessages[error]}}
+ {{ errorMessages[error] | translate }}
{{ 'core.login.invalidvaluemax' | translate:{$a: control.errors!.max.max} }}
diff --git a/src/core/components/input-errors/input-errors.ts b/src/core/components/input-errors/input-errors.ts
index 117867649..570386555 100644
--- a/src/core/components/input-errors/input-errors.ts
+++ b/src/core/components/input-errors/input-errors.ts
@@ -14,7 +14,6 @@
import { Component, ElementRef, HostBinding, Input, OnChanges, OnInit, SimpleChange } from '@angular/core';
import { FormControl } from '@angular/forms';
-import { Translate } from '@singletons';
/**
* Component to show errors if an input isn't valid.
@@ -30,8 +29,7 @@ import { Translate } from '@singletons';
* Example usage:
*
*
- * {{ 'core.login.username' | translate }}
- *
+ *
*
*
*/
@@ -42,12 +40,12 @@ import { Translate } from '@singletons';
})
export class CoreInputErrorsComponent implements OnInit, OnChanges {
- @Input() control?: FormControl;
- @Input() errorMessages: Record = {};
+ @Input() control?: FormControl; // Needed to be able to check the validity of the input.
+ @Input() errorMessages: Record = {}; // Error messages to show. Keys must be the name of the error.
@Input() errorText = ''; // Set other non automatic errors.
errorKeys: string[] = [];
- protected element: HTMLElement;
+ protected hostElement: HTMLElement;
@HostBinding('class.has-errors')
get hasErrors(): boolean {
@@ -59,31 +57,60 @@ export class CoreInputErrorsComponent implements OnInit, OnChanges {
constructor(
element: ElementRef,
) {
- this.element = element.nativeElement;
+ this.hostElement = element.nativeElement;
}
/**
* Initialize some common errors if they aren't set.
*/
protected initErrorMessages(): void {
- this.errorMessages.required = this.errorMessages.required || Translate.instant('core.required');
- this.errorMessages.email = this.errorMessages.email || Translate.instant('core.login.invalidemail');
- this.errorMessages.date = this.errorMessages.date || Translate.instant('core.login.invaliddate');
- this.errorMessages.datetime = this.errorMessages.datetime || Translate.instant('core.login.invaliddate');
- this.errorMessages.datetimelocal = this.errorMessages.datetimelocal || Translate.instant('core.login.invaliddate');
- this.errorMessages.time = this.errorMessages.time || Translate.instant('core.login.invalidtime');
- this.errorMessages.url = this.errorMessages.url || Translate.instant('core.login.invalidurl');
+ this.errorMessages = {
+ required: this.errorMessages.required || 'core.required',
+ email: this.errorMessages.email || 'core.login.invalidemail',
+ date: this.errorMessages.date || 'core.login.invaliddate',
+ datetime: this.errorMessages.datetime || 'core.login.invaliddate',
+ datetimelocal: this.errorMessages.datetimelocal || 'core.login.invaliddate',
+ time: this.errorMessages.time || 'core.login.invalidtime',
+ url: this.errorMessages.url || 'core.login.invalidurl',
+ // Set empty values by default, the default error messages will be built in the template when needed.
+ max: this.errorMessages.max || '',
+ min: this.errorMessages.min || '',
+ };
- // Set empty values by default, the default error messages will be built in the template when needed.
- this.errorMessages.max = this.errorMessages.max || '';
- this.errorMessages.min = this.errorMessages.min || '';
+ this.errorMessages.requiredTrue = this.errorMessages.required;
+
+ this.errorKeys = Object.keys(this.errorMessages);
}
/**
* @inheritdoc
*/
ngOnInit(): void {
- this.element.closest('ion-item')?.classList.add('has-core-input-errors');
+ const parent = this.hostElement.parentElement;
+ let item: HTMLElement | null = null;
+
+ if (parent?.tagName === 'ION-ITEM') {
+ item = parent;
+
+ // Get all elements on the parent and wrap them with a div.
+ // This is needed because otherwise the error message will be shown on the right of the input. Or overflowing the item.
+ const wrapper = document.createElement('div');
+
+ wrapper.classList.add('core-input-errors-wrapper');
+
+ Array.from(parent.children).forEach((child) => {
+ if (!child.slot) {
+ wrapper.appendChild(child);
+ }
+ });
+
+ parent.appendChild(wrapper);
+ } else {
+ item = this.hostElement.closest('ion-item');
+ }
+
+ item?.classList.add('has-core-input-errors');
+
}
/**
@@ -92,11 +119,6 @@ export class CoreInputErrorsComponent implements OnInit, OnChanges {
ngOnChanges(changes: { [name: string]: SimpleChange }): void {
if ((changes.control || changes.errorMessages) && this.control) {
this.initErrorMessages();
-
- this.errorKeys = this.errorMessages ? Object.keys(this.errorMessages) : [];
- }
- if (changes.errorText) {
- this.errorText = changes.errorText.currentValue;
}
}
diff --git a/src/core/components/mark-required/mark-required.ts b/src/core/components/mark-required/mark-required.ts
index 5b72cf378..f0bc34b51 100644
--- a/src/core/components/mark-required/mark-required.ts
+++ b/src/core/components/mark-required/mark-required.ts
@@ -37,13 +37,13 @@ export class CoreMarkRequiredComponent implements OnInit, AfterViewInit {
@Input('core-mark-required') coreMarkRequired: boolean | string = true;
- protected element: HTMLElement;
+ protected hostElement: HTMLElement;
requiredLabel = Translate.instant('core.required');
constructor(
element: ElementRef,
) {
- this.element = element.nativeElement;
+ this.hostElement = element.nativeElement;
}
/**
@@ -59,18 +59,21 @@ export class CoreMarkRequiredComponent implements OnInit, AfterViewInit {
ngAfterViewInit(): void {
if (this.coreMarkRequired) {
// Add the "required" to the aria-label.
- const ariaLabel = this.element.getAttribute('aria-label') ||
- CoreTextUtils.cleanTags(this.element.innerHTML, { singleLine: true });
+ const ariaLabel = this.hostElement.getAttribute('aria-label') ||
+ CoreTextUtils.cleanTags(this.hostElement.innerHTML, { singleLine: true });
if (ariaLabel) {
- this.element.setAttribute('aria-label', ariaLabel + ' ' + this.requiredLabel);
+ this.hostElement.setAttribute('aria-label', ariaLabel + '. ' + this.requiredLabel);
}
} else {
// Remove the "required" from the aria-label.
- const ariaLabel = this.element.getAttribute('aria-label');
+ const ariaLabel = this.hostElement.getAttribute('aria-label');
if (ariaLabel) {
- this.element.setAttribute('aria-label', ariaLabel.replace(' ' + this.requiredLabel, ''));
+ this.hostElement.setAttribute('aria-label', ariaLabel.replace('. ' + this.requiredLabel, ''));
}
}
+
+ const input = this.hostElement.closest('ion-input, ion-textarea');
+ input?.setAttribute('required', this.coreMarkRequired ? 'true' : 'false');
}
}
diff --git a/src/core/features/login/pages/email-signup/email-signup.ts b/src/core/features/login/pages/email-signup/email-signup.ts
index 8938b13eb..43797e233 100644
--- a/src/core/features/login/pages/email-signup/email-signup.ts
+++ b/src/core/features/login/pages/email-signup/email-signup.ts
@@ -105,15 +105,14 @@ export class CoreLoginEmailSignupPage implements OnInit {
});
// Setup validation errors.
- this.usernameErrors = CoreLoginHelper.getErrorMessages('core.login.usernamerequired');
- this.passwordErrors = CoreLoginHelper.getErrorMessages('core.login.passwordrequired');
- this.emailErrors = CoreLoginHelper.getErrorMessages('core.login.missingemail');
- this.policyErrors = CoreLoginHelper.getErrorMessages('core.login.policyagree');
- this.email2Errors = CoreLoginHelper.getErrorMessages(
- 'core.login.missingemail',
- undefined,
- 'core.login.emailnotmatch',
- );
+ this.usernameErrors = { required: 'core.login.usernamerequired' };
+ this.passwordErrors = { required: 'core.login.passwordrequired' };
+ this.emailErrors = { required: 'core.login.missingemail' };
+ this.policyErrors = { required: 'core.login.policyagree' };
+ this.email2Errors = {
+ required: 'core.login.missingemail',
+ pattern: 'core.login.emailnotmatch',
+ };
}
/**
@@ -224,7 +223,7 @@ export class CoreLoginEmailSignupPage implements OnInit {
const namefieldsErrors = {};
if (this.settings.namefields) {
this.settings.namefields.forEach((field) => {
- namefieldsErrors[field] = CoreLoginHelper.getErrorMessages('core.login.missing' + field);
+ namefieldsErrors[field] = { required: 'core.login.missing' + field };
});
}
this.namefieldsErrors = namefieldsErrors;
diff --git a/src/core/features/login/services/login-helper.ts b/src/core/features/login/services/login-helper.ts
index aed48d583..a8c22c345 100644
--- a/src/core/features/login/services/login-helper.ts
+++ b/src/core/features/login/services/login-helper.ts
@@ -252,60 +252,6 @@ export class CoreLoginHelperProvider {
return CoreTextUtils.treatDisabledFeatures(disabledFeatures);
}
- /**
- * Builds an object with error messages for some common errors.
- * Please notice that this function doesn't support all possible error types.
- *
- * @param requiredMsg Code of the string for required error.
- * @param emailMsg Code of the string for invalid email error.
- * @param patternMsg Code of the string for pattern not match error.
- * @param urlMsg Code of the string for invalid url error.
- * @param minlengthMsg Code of the string for "too short" error.
- * @param maxlengthMsg Code of the string for "too long" error.
- * @param minMsg Code of the string for min value error.
- * @param maxMsg Code of the string for max value error.
- * @returns Object with the errors.
- */
- getErrorMessages(
- requiredMsg?: string,
- emailMsg?: string,
- patternMsg?: string,
- urlMsg?: string,
- minlengthMsg?: string,
- maxlengthMsg?: string,
- minMsg?: string,
- maxMsg?: string,
- ): Record {
- const errors: Record = {};
-
- if (requiredMsg) {
- errors.required = errors.requiredTrue = Translate.instant(requiredMsg);
- }
- if (emailMsg) {
- errors.email = Translate.instant(emailMsg);
- }
- if (patternMsg) {
- errors.pattern = Translate.instant(patternMsg);
- }
- if (urlMsg) {
- errors.url = Translate.instant(urlMsg);
- }
- if (minlengthMsg) {
- errors.minlength = Translate.instant(minlengthMsg);
- }
- if (maxlengthMsg) {
- errors.maxlength = Translate.instant(maxlengthMsg);
- }
- if (minMsg) {
- errors.min = Translate.instant(minMsg);
- }
- if (maxMsg) {
- errors.max = Translate.instant(maxMsg);
- }
-
- return errors;
- }
-
/**
* Get logo URL from a site public config.
*
diff --git a/src/theme/theme.base.scss b/src/theme/theme.base.scss
index 929209ef8..c50f2471a 100644
--- a/src/theme/theme.base.scss
+++ b/src/theme/theme.base.scss
@@ -126,6 +126,10 @@ ion-item > .in-item,
white-space: normal !important;
}
+ion-item .core-input-errors-wrapper {
+ width: 100%;
+}
+
@each $color-name, $unused in $colors {
.text-#{$color-name},
p.text-#{$color-name} {
diff --git a/upgrade.txt b/upgrade.txt
index 76fb4cca7..f188871bc 100644
--- a/upgrade.txt
+++ b/upgrade.txt
@@ -10,6 +10,7 @@ For more information about upgrading, read the official documentation: https://m
- Removed CoreToLocaleStringPipe deprecated since 3.6.0
- With the upgrade to Ionic 7 ion-slides is no longer supported and now you need to use swiper-container and swiper-slide. More info here: https://ionicframework.com/docs/angular/slides
- With the upgrade to Ionic7 ion-datetime has changed its usage. We recommend using ion-datetime-button. More info here: https://ionicframework.com/docs/updating/6-0#datetime
+ - CoreLoginHelper.getErrorMessages has been removed. Please create the messages object yourself.
=== 4.3.0 ===