[[{“value”:”
Hi Everyone,
Hope you are doing well.
In this blog, I am going to explain how to create and use a Message Popover in a SAPUI5 application.
What is a Message Popover?
A Message Popover is a control that is used to display errors, warnings, success messages, and informational messages to users in a centralized location.
Consider a scenario where a user is signing up and needs to enter details such as their name, phone number, and email address. These fields must be validated to ensure that the entered information is correct.
For example, while entering a name, if the user includes numbers or special characters, the validation should fail. In such cases, an error message can be displayed directly below the input field using the ValueStateText property.
However, when there are multiple validation errors across different fields, displaying messages individually may not provide the best user experience. In such situations, a Message Popover can be used to display all validation messages in one place, making it easier for users to review and resolve them.
Application Overview
To demonstrate the Message Popover functionality, I have created a simple Login application.
The folder structure of the application looks like this:
The application consists of:
- One View – Contains the login form and footer button.
- One Fragment – Used to display the Message Popover.
Additionally, I have used three models:
- Button Visibility Model – Controls the visibility of the Message Popover button.
- Button Type Model – Controls the button type based on the severity of the messages.
- mPopover Model – Stores and displays validation messages in the Message Popover.
Using these components, users can view all validation messages in a centralized Message Popover instead of checking each field individually.
Login Form Implementation
I have created a Login form in the view. The form contains two input fields: one for the phone number and another for the password. It also includes a Login button.
Initially, the Login button is hidden. As the user enters the required credentials, validations are performed on both input fields. Once all validation conditions are satisfied and no errors are present, the Login button becomes visible.
In the footer, I have added a Message Popover button. This button is also hidden by default and becomes visible only when there are validation messages to display.
The button displays the total number of messages and dynamically changes its type based on the highest message severity, such as Error, Warning, Success, or Information.
To achieve this functionality, I have used the Button Visibility Model to control the visibility of the Message Popover button and the Button Type Model to manage the button type according to the message severity.
View and Model Configuration
Now, let’s look at the View implementation used in this application.
The code below shows the View1 implementation, which contains the login form and the footer button.
<mvc:View xmlns:core=”sap.ui.core”
xmlns:form=”sap.ui.layout.form”
xmlns:smartform=”sap.ui.comp.smartform”
xmlns:f=”sap.f” controllerName=”messagepopover.controller.View1″
xmlns:mvc=”sap.ui.core.mvc” displayBlock=”true”
xmlns=”sap.m”>
<Page id=”page” title=”{i18n>title}”>
<content />
<form:SimpleForm editable=”true” class=’loginFormClass’ id=”loginFormClass”>
<Label id=”_IDGenLabel1″ ></Label>
<Input placeholder=”Enter Your Phone Number” width=”300px” liveChange=”onChangePhoneNumber” id=”loginFragmentPhonNumberInput”></Input>
<Label id=”_IDGenLabel2″ ></Label>
<Input placeholder=”Enter Your Password” width=”300px” liveChange=”onChangePassword” id=”loginFragmentPasswordInput”></Input>
<Label id=”_IDGenLabel3″ ></Label>
<Button id=”_IDGenButton4″ text=”Login” type=”Emphasized” press=”handleLoginButton” visible=”{buttonVisibilityModel>/loginButtonInFragment}” width=”300px”></Button>
</form:SimpleForm>
<footer>
<OverflowToolbar id=”_IDGenOverflowToolbar” >
<Button id=”_IDGenButton5″ press=”handleMessagePopover” text= “{path: ‘mPopOver>/aMockMessage’, formatter: ‘.highestSeverityMessages’ }” type=”{ path: ‘mPopOver>/aMockMessage’, formatter: ‘.buttonTypeFormatter’ }”></Button>
</OverflowToolbar>
</footer>
</Page>
</mvc:View>
The screenshot below shows the models configured in the manifest.json file. These models are used throughout the application to control button visibility, button type, and the messages displayed in the Message Popover.
The following code snippet shows the data maintained in the Button Visibility Model. This model is responsible for controlling the visibility of the Message Popover button.
{
“loginButtonInFragment”:false
}
The following code snippet shows the data maintained in the Button Type Model. This model is used to dynamically determine the button type based on the severity of the messages.
{
“messagePopOverButtonType”: “Error”
}
The following code snippet shows the data maintained in the mPopover Model. This model stores the messages displayed in the Message Popover, including their type, title, and description.
{
“aMockMessage”: []
}
Phone Number Validation
Now, let’s look at the validation logic for the phone number field.
I have attached a liveChange event to the phone number input field so that validation is performed as the user types.
Within this function, I validate multiple scenarios, such as checking whether the field is empty, ensuring that only numeric values are entered, and verifying that the phone number meets the required length.
If any validation condition fails, the corresponding error message is added to the mPopover Model. These messages are then displayed in the Message Popover, allowing users to view all validation errors in a single place.
The code snippet below shows the implementation of the onChangePhoneNumber function.
onChangePhoneNumber: function (oEvent) {
debugger
const phoneNumber = oEvent.getParameter(“value”)?.trim()||””;
const buttonVisibilityModel = this.getView().getModel(“buttonVisibilityModel”);
const oMessageModel = this.getView().getModel(“mPopOver”);
const buttonTypeModel = this.getView().getModel(“buttonTypeModel”);
let aMessages = oMessageModel.getProperty(“/aMockMessage”)
.filter(msg => msg.field !== “phone”);
const validations = [
{
test: v => !v,
type: “Error”,
title: “Phone number is required”,
description: “Please enter your phone number”
},
{
test: v => v.length !== 10,
type: “Error”,
title: “Phone number must be 10 digits”,
description: “Enter exactly 10 digits”
},
{
test: v => !/^d+$/.test(v),
type: “Error”,
title: “Invalid characters”,
description: “Phone number must contain only digits”
},
{
test: v => !/^[6-9]d{9}$/.test(v),
type: “Error”,
title: “Invalid phone number”,
description: “Indian phone numbers must start with 6–9”
},
{
test: v => /^(d)1{9}$/.test(v),
type: “Warning”,
title: “Suspicious phone number”,
description: “Number seems repetitive, please check again”
}
];
const failedRules = validations.filter(rule => rule.test(phoneNumber));
if (failedRules.length > 0) {
failedRules.forEach(rule => {
aMessages.push({
field: “phone”,
type: rule.type,
title: rule.title,
description: rule.description
});
});
const hasError = failedRules.some(rule => rule.type === “Error”);
oEvent.getSource().setValueState(hasError ? “Error” : “Warning”);
buttonTypeModel.setProperty(
“/message_pop_overButtonType”,
hasError ? “Error” : “Warning”
);
phoneNumberFlag = !hasError;
} else {
oEvent.getSource().setValueState(“None”);
oEvent.getSource().setValueStateText(“”);
phoneNumberFlag = true;
}
oMessageModel.setProperty(“/aMockMessage”, aMessages);
buttonVisibilityModel.setProperty(
“/loginButtonInFragment”,
phoneNumberFlag && passwordFlag
);
}
Password Validation
Similarly, I have implemented the onChangePassword function and attached it to the password input field using the liveChange event.
This function validates the password against all required criteria, such as checking whether the field is empty, verifying the minimum password length, and ensuring that the password meets the expected format.
Whenever a validation rule is not satisfied, the corresponding message is added to the mPopover Model. These messages are then displayed in the Message Popover, providing users with clear feedback about the issues that need to be resolved.
The code snippet below shows the implementation of the onChangePassword function.
onChangePassword: function (oEvent) {
debugger
const password = oEvent.getParameter(“value”)?.trim() || “”;
const buttonVisibilityModel = this.getView().getModel(“buttonVisibilityModel”);
const oMessageModel = this.getView().getModel(“mPopOver”);
const buttonTypeModel = this.getView().getModel(“buttonTypeModel”);
let aMessages = oMessageModel.getProperty(“/aMockMessage”)
.filter(msg => msg.field !== “password”);
const validations = [
{
test: v => !v,
type: “Error”,
title: “Password is required”,
description: “Please enter your password”
},
{
test: v => v.length < 8,
type: “Error”,
title: “Too short”,
description: “Password must be at least 8 characters long”
},
{
test: v => !/[A-Z]/.test(v),
type: “Error”,
title: “Missing uppercase letter”,
description: “Password must contain at least one uppercase letter”
},
{
test: v => !/[a-z]/.test(v),
type: “Error”,
title: “Missing lowercase letter”,
description: “Password must contain at least one lowercase letter”
},
{
test: v => !/d/.test(v),
type: “Error”,
title: “Missing number”,
description: “Password must contain at least one number”
},
{
test: v => !/[!@#$%^&*(),.?”:{}|<>]/.test(v),
type: “Error”,
title: “Missing special character”,
description: “Password must contain at least one special character”
},
{
test: v => /s/.test(v),
type: “Error”,
title: “Contains whitespace”,
description: “Password must not contain spaces”
},
{
test: v => /^([a-zA-Z0-9!@#$%^&*])1{7,}$/.test(v),
type: “Warning”,
title: “Weak password”,
description: “Password is repetitive and easy to guess”
}
];
const failedRules = validations.filter(rule => rule.test(password));
if (failedRules.length > 0) {
failedRules.forEach(rule => {
aMessages.push({
field: “password”,
type: rule.type,
title: rule.title,
description: rule.description
});
});
const hasError = failedRules.some(rule => rule.type === “Error”);
oEvent.getSource().setValueState(hasError ? “Error” : “Warning”);
buttonTypeModel.setProperty(
“/message_pop_overButtonType”,
hasError ? “Error” : “Warning”
);
passwordFlag = !hasError;
} else {
oEvent.getSource().setValueState(“None”);
oEvent.getSource().setValueStateText(“”);
passwordFlag = true;
}
oMessageModel.setProperty(“/aMockMessage”, aMessages);
buttonVisibilityModel.setProperty(
“/loginButtonInFragment”,
phoneNumberFlag && passwordFlag
);
}
Message Popover Fragment
Whenever a validation error occurs, I add the corresponding message to the mPopover Model.
Based on the messages available in the model, the footer button dynamically displays the total number of messages and their severity type.
When the user clicks the footer button, a Message Popover Fragment is opened. This fragment is bound to the mPopover Model and displays all validation messages in a centralized location, making it easier for users to review and resolve issues.
The code snippet below shows the implementation of the Message Popover Fragment.
<core:FragmentDefinition xmlns=”sap.m”
xmlns:core=”sap.ui.core”>
<MessagePopover id=”_IDGenMessagePopover” items=”{mPopOver>/aMockMessage/}” afterClose=”handleMessagePopoverClose”>
<items >
<MessageItem id=”_IDGenMessageItem” type=”{mPopOver>type}” title=”{mPopOver>title}” activeTitle=”{mPopOver>active}” description=”{mPopOver>description}” subtitle=”{mPopOver>subtitle}” counter=”{mPopOver>counter}”></MessageItem>
</items>
</MessagePopover>
</core:FragmentDefinition>
Opening the Message Popover
To display the messages stored in the mPopover Model, I have created a function called handleMessagePopover.
This function is triggered when the user clicks the Message Popover button available in the footer.
Inside this function, the Message Popover Fragment is loaded and opened. Since the fragment is bound to the mPopover Model, it automatically displays all validation messages, including errors, warnings, success messages, and informational messages.
By centralizing all messages within the Message Popover, users can easily review and resolve validation issues without having to check each field individually.
The code snippet below shows the implementation of the handleMessagePopover function.
handleMessagePopover: async function (oEvent) {
debugger
this.oDialog = await this.loadFragment({
name: “messagepopover.fragments.messagePopover”,
}).then(function (oDialog) {
return oDialog;
});
this.oDialog.openBy(oEvent.getSource());
}
I have used two formatters in Button in footer one is “highestSeverityMessages” and another one is “buttonTypeFormatter”
Code snippet of “highestSeverityMessages”
highestSeverityMessages: function () {
debugger
var sHighestSeverityIconType = this.buttonTypeFormatter();
var sHighestSeverityMessageType;
switch (sHighestSeverityIconType) {
case “Negative”:
sHighestSeverityMessageType = “Error”;
break;
case “Critical”:
sHighestSeverityMessageType = “Warning”;
break;
case “Success”:
sHighestSeverityMessageType = “Success”;
break;
default:
sHighestSeverityMessageType = !sHighestSeverityMessageType ? “Information” : sHighestSeverityMessageType;
break;
}
return this.getView().getModel(‘mPopOver’).oData.aMockMessage.reduce(function (iNumberOfMessages, oMessageItem) {
return oMessageItem.type === sHighestSeverityMessageType ? ++iNumberOfMessages : iNumberOfMessages;
}, ” “);
}
code snippet of “buttonTypeFormatter”
buttonTypeFormatter: function () {
debugger
var sHighestSeverityIcon;
var aMessages = this.getView().getModel(‘mPopOver’).getData().aMockMessage;
if (aMessages) {
aMessages.forEach(function (sMessage) {
switch (sMessage.type) {
case “Error”:
sHighestSeverityIcon = “Negative”;
break;
case “Warning”:
sHighestSeverityIcon = sHighestSeverityIcon !== “Negative” ? “Critical” : sHighestSeverityIcon;
break;
case “Success”:
sHighestSeverityIcon = sHighestSeverityIcon !== “Negative” && sHighestSeverityIcon !== “Critical” ? “Success” : sHighestSeverityIcon;
break;
default:
sHighestSeverityIcon = !sHighestSeverityIcon ? “Neutral” : sHighestSeverityIcon;
break;
}
});
return sHighestSeverityIcon;
} else {
return sHighestSeverityIcon = “Default”;
}
}
This is how I have implemented MessagePopover
Conclusion
Message Popover is a useful SAPUI5 control for displaying validation messages in a centralized and user-friendly manner. Instead of showing individual error messages across multiple fields, it provides a single location where users can view and manage all messages efficiently.
In this blog, we explored how to implement a Message Popover using a simple Login application. We covered input validation using the liveChange event, storing validation messages in a dedicated model, dynamically controlling the visibility and type of the Message Popover button, and displaying messages through a reusable fragment.
By implementing Message Popover in your applications, you can improve the overall user experience and provide clear, consistent feedback to users during data entry and validation processes.
I hope this blog helps you understand and implement Message Popover in your SAPUI5 applications. Thank you for reading, and feel free to share your feedback or suggestions in the comments section.
“}]]
Read More Technology Blog Posts by Members articles
#abap