SAPUI5 Message – Mejorando el feedback al usuario

Introducción

Nota: esta entrada la publiqué de manera resumida en el blog de SAP y se «viralizó» (ya que la cuenta de SAP Developers de twitter la publicó), por lo que parte del contenido os sonará. Aquí la entrada (en inglés)

Cuando creamos una UX una de las cosas que mas se van a repetir es el control de errores y el posterior feedback de nuestro software al usuario. Paremos un momento a reflexionar, ¿que hacemos?… ¿Mostramos mensajes de error? ¿Pintamos los campos con colores? ¿Popups?

Repaso general de tipos de mensajes

Pero antes… Un breve repaso a todas las librerías de mensajes de SAPUI5, y como se muestran los distintos controles. La lista que os muestro son los componentes mas usados en la ultima versión de Fiori 3 aunque algunos ya son viejos conocidos de Fiori 1 y 2:

Hasta aquí la teoria, lo que sigue es la implementación de los mensajes anteriores


Manos a la obra

Lo primero, como es costumbre sera crear un proyecto SAPUI5 utilizando el template de SAP WEBIDE.

Una vez tengamos el proyecto básico vamos a crear un formulario de datos y añadiremos un modelo de datos:

  • En nuestro controlador, en la función onInit añadiremos:
        // create a default model with somde demo data
        oModel = new JSONModel({
            MandatoryInputValue: "",
            DateValue: null,
            IntegerValue: undefined,
            Dummy: ""
        });
        oModel.setDefaultBindingMode(BindingMode.TwoWay);
        oView.setModel(oModel);
  • Y nuestra vista, tendra el siguiente aspecto:
<f:Form id="form" editable="true" title="UI Messages">
 <f:layout>
  <f:ResponsiveGridLayout/>
  </f:layout>
 <f:formContainers>
  <f:FormContainer id="formContainer" title="Fields">
   <f:FormElement>
    <f:label>
     <Label text="Nombre" required="true"/>
    </f:label>
    <f:fields>
     <Input id="Nombre" value="{/MandatoryInputValue}"/>
    </f:fields>
   </f:FormElement>
   <f:FormElement>
    <f:label>
     <Label text="Fecha"/>
    </f:label>
    <f:fields>
     <DatePicker id="date" value="{/DateValue}"/>
    </f:fields>
   </f:FormElement>
   <f:FormElement>
    <f:label>
     <Label text="Valoración (0-10)"/>
    </f:label>
    <f:fields>
     <Input id="int" value="{/IntegerValue'}"/>
    </f:fields>
   </f:FormElement>
  </f:FormContainer>
 </f:formContainers>
</f:Form>

De momento solo tenemos una pantalla con un formulario. Vamos a añadirle mensajes de aviso y control, ahora empieza lo bueno:

Añadiendo un mensaje de aviso fijo

Para añadir un mensaje del tipo message strip bastara con añadir el siguiente código en nuestra vista:

<MessageStrip
    text="Este formulario es provisional"
    type="Warning"
    showIcon="true"
    showCloseButton="true"
    class="sapUiMediumMarginBottom">
</MessageStrip>

El resultado, al acceder a la pantalla es el siguiente:

Añadiendo un popup de aviso en el centro de la pantalla

Para añadir este tipo de mensaje llamado message box únicamente es necesario disparar el mensaje con el controlador, para ello, deberemos realizar dos pasos, importar la librería y lanzar el mensaje:

Añadimos la libreria al controlador (sap/m/MessageBox):

sap.ui.define([
     "sap/ui/core/mvc/Controller",
     "sap/ui/model/json/JSONModel",
     "sap/ui/model/BindingMode",
     "sap/ui/core/message/Message",
     'sap/m/MessageBox'
 ], function (Controller,JSONModel,BindingMode,Message,MessageBox) {

Para poder lanzar el mensaje añadiremos un boton, aunque podriamos añadirlo en la función onInit:

    lanzarMessageBox: function(oEvent) {
        var bCompact = !!this.getView().$().closest(".sapUiSizeCompact").length;
        MessageBox.confirm(
            "Seguro que quieres cerrar esta ventana?", {
                styleClass: bCompact ? "sapUiSizeCompact" : ""
            }
        );
    },

Hay varios tipos de MessageBox: confirmación, error, información… Solo hay que buscar el mas adecuado en la librería.

Para lanzar el mensaje añadiremos a la vista un boton como disparador (es solo un ejemplo de como lanzar el mensaje, pero des del controlador lo podemos iniciar cuando lo necesitemos):

<Button
 text="Message Box"
 class="sapUiSmallMarginBottom"
 press="lanzarMessageBox"
width="250px"/>

El resultado al pulsar el botón es el siguiente:

El mensaje más sutil

Este mensaje aparece y desaparece de manera discreta, se llama Message Toast. Como en el caso anterior se lanza vía controlador, pero no es necesario que el usuario realice ninguna acción. Eso si, necesita un controlador para iniciarlo.

Como en el caso anterior realizaremos dos simples acciones, añadir la librería y disparar el mensaje (sap/m/MessageToast):

sap.ui.define([
	"sap/ui/core/mvc/Controller",
	"sap/ui/model/json/JSONModel",
	"sap/ui/model/BindingMode",
	"sap/ui/core/message/Message",
	"sap/m/MessageBox",
	"sap/m/MessageToast"
], function (Controller,JSONModel,BindingMode,Message,MessageBox,MessageToast) {
	"use strict";

En este caso, para lanzar el mensaje lo añadiremos en el onINIT (esto es solo un ejemplo, como en el caso anterior, lo podemos añadir a un boton, una llamada, o lo que se nos ocurra 😉 )

onInit: function () {
	MessageToast.show("Hola, has iniciado el controlador :) ");
...

El resultado es el siguiente:

El más completo y con más detalle

El último de los mensajes que os enseños, aunque esta en la documentación oficial como mensaje, tiene su truco, en verdad es un popup donde podemos añadir lo que queramos, pero SAP nos ofrece un código a modo plantilla donde se muestran los distintos errores.

El secreto de este tipo de mensaje es que se combina con un modelo estándar de mensajes y eventos que nos permite detectar un error en un campo tipo input, marcarlos y mostrar un detalle.

Es el mas complejo, pero tampoco puede presumir de ser dificil de implementar.

Necesitaremos estas dos librerías, una para el control de mensajes, la otra para el bindeo bi-direccional de los datos (two way binding) esto sera necesario para que se apliquen las modificaciones en el modelo:

sap.ui.define([
	"sap/ui/core/mvc/Controller",
	"sap/ui/model/json/JSONModel",
	"sap/ui/model/BindingMode",
	"sap/ui/core/message/Message",
], function (Controller,JSONModel,BindingMode,Message) {

Al iniciar el controlador, necesitaremos iniciar todos los componentes en la función onINIT():

onInit: function () {		
            var oMessageManager, oModel, oView;
			
	    //Obtenemos la vista actual
            oView = this.getView();

            // Iniciamos un modelo de mensajes (donde guardaremos los datos)
            oMessageManager = sap.ui.getCore().getMessageManager();
            oView.setModel(oMessageManager.getMessageModel(), "message");
            
            // Registramos el disparador a la vista actual
            oMessageManager.registerObject(oView, true);
            
            // create a default model with somde demo data (esto solo es para los campos de input)
            oModel = new JSONModel({
                MandatoryInputValue: "",
                DateValue: null,
                IntegerValue: undefined,
                Dummy: ""
            });
            //Fijamos el modelo bidireccional
            oModel.setDefaultBindingMode(BindingMode.TwoWay);
            //Añadimos el modelo a la vista
            oView.setModel(oModel);

Obviamente, la parte del modelo en este ejemplo la añadiremos en el onInit a modo de ejemplo, pero podría ser directamente un oDATA.

El siguiente paso es definir un disparador para fragment donde se alojara el listado con el detalle de errores y mensajes que el usuario podrá ver (lo definiremos después), como os decía, tiramos directamente de template

_getMessagePopover : function () {
        // create popover lazily (singleton)
        if (!this._oMessagePopover) {
            this._oMessagePopover = sap.ui.xmlfragment(this.getView().getId(),"<namespace_de_la_aplicación>.fragments.MessageError", this);
            this.getView().addDependent(this._oMessagePopover);
        }
        return this._oMessagePopover;
    }

Ya podemos crear un nuevo fragment, en mi caso, he creado una nueva carpeta en el proyecto llamada fragments y allí he puesto el fragment:

<core:FragmentDefinition
    xmlns="sap.m"
    xmlns:core="sap.ui.core">
    <MessagePopover
        items="{message>/}"
        initiallyExpanded="true">
        <MessageItem
            type="{message>type}"
            title="{message>message}"
            subtitle="{message>additionalText}"
            description="{message>description}"/>
    </MessagePopover>
</core:FragmentDefinition>

Como veis, el componente utiliza el modelo de mensajes definido anteriormente «Message». En este punto hay que tener cuidado ya que en la documentación oficial, en el momento de escribir el blog no esta actualizada, usaremos «MessageItem» (que es el componente mas nuevo).

Y ya solo nos queda añadir las validaciones, para este caso, utilizaremos validaciones estándar. En los campos input de nuestro formulario hay que añadir formatters para la validación:

<f:FormElement>
	<f:label>
		<Label text="Nombre" required="true"/>
	</f:label>
	<f:fields>
		<Input id="Nombre" value="{ path: '/MandatoryInputValue', type: 'sap.ui.model.type.String', constraints: { minLength: 3 } }"/>
	</f:fields>
</f:FormElement>
<f:FormElement>
	<f:label>
		<Label text="Fecha"/>
	</f:label>
	<f:fields>
		<DatePicker id="date"
			value="{ path:'/DateValue', type:'sap.ui.model.type.Date', formatOptions: { style: 'short', strictParsing: true }, constraints: { } }"/>
	</f:fields>
</f:FormElement>
<f:FormElement>
	<f:label>
		<Label text="Valoración (0-10)"/>
	</f:label>
	<f:fields>
		<Input id="int" value="{ path: '/IntegerValue', type:'sap.ui.model.type.Integer', constraints: { minimum: 0, maximum: 10 } }"/>
	</f:fields>
</f:FormElement>

De los 3 campos que hemos añadido, solo 2 nos pueden mostrar errores, el de fecha obliga al usuario a añadir bien el formato.

Los otros dos son:

  • Nombre: Validaremos que sea un tipo string con un minimo de 3.caracteres
  • int: Validaremos que sea un entero entre 0 y 10.

¡Nos queda un paso! avisar al usuario en caso de errores, por lo que no lo vamos a molestar si todo esta correcto, para ello, en el footer añadiremos un boton pero condicionado al numero de registros del modelo «message» que contiene los mensajes:

<Toolbar id="otbFooter">
  <Button icon="sap-icon://alert" text="{= ${message>/}.length }" visible="{= ${message>/}.length > 0 }" type="Emphasized" press="onMessagePopoverPress"/>
</Toolbar>

El boton solo sera visible si hay mas de 0 mensajes. Y en caso que aparezca llamaremos al controlador para iniciar el componente tipo listado de errores. este sera el resultado final:

No solo tendremos el número de errores y su detalle, sino que se marcará en la pantalla para que el usuario vea mas rápido donde están los errores.


Hasta aquí este repaso de mensajes en SAPUI5, en mi opinión con estos tipos podemos cubrir todas las causticas, pero también podemos importar otras librerías externas o crear nuestros propios componentes, en funcion del tiempo y los requisitos.

Quieres estar a la última… Suscribete

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.