#SAPUI5#Fiori#MVC#Arquitectura

Arquitectura MVC en SAPUI5: por qué el controlador no es el cubo de basura

Vista, modelo y controlador tienen fronteras claras. Cuando las respetas, la app se mantiene sola; cuando no, el controlador acaba con 800 líneas de todo. Lo vemos con código XML y JavaScript real.

Por Logali Tech 2 min de lectura

La mayoría de las apps SAPUI5 que heredamos no fallan por el framework. Fallan porque alguien metió en el controlador todo lo que no sabía dónde poner: lógica de UI, transformación de datos, textos hardcodeados y hasta el esquema del modelo. El patrón Model-View-Controller de UI5 existe justo para evitar eso, y respetarlo cuesta menos que saltárselo.

Las tres piezas y su única responsabilidad

  • View (.view.xml): declara qué se ve. XML puro, sin lógica. Un <Button>, un <List>, un binding. Si estás escribiendo un if en la vista, algo va mal.
  • Controller (.controller.js): reacciona a eventos. onShowHello, onFilterInvoices. Orquesta, no almacena estado de negocio.
  • Model: es el dato. Un JSONModel, un ODataModel o el ResourceModel de i18n. La vista se vincula a él; el controlador lo lee y lo escribe.

La regla que nos ahorra discusiones en cada revisión de código: la vista nunca conoce al modelo por su forma interna, solo por su binding path; el controlador nunca construye HTML.

flowchart TB
 V["View XML declara la UI"] -->|"eventos: press, search"| C["Controller orquesta"]
 C -->|"lee y escribe"| M["Model JSON, OData, i18n"]
 M -->|"data binding"| V
 C -->|"setModel"| V

El controlador como debe ser

Fíjate en este controlador real: declara sus dependencias, extiende Controller y expone handlers cortos. Nada más.

sap.ui.define([
    "sap/ui/core/mvc/Controller",
    "sap/m/MessageToast",
    "sap/ui/model/json/JSONModel"
],
function (Controller, MessageToast, JSONModel) {
    "use strict";
    return Controller.extend("logaligroup.SAPUI5.controller.App", {
        onInit: function () {
            var oModel = new JSONModel({ recipient: { name: "World" } });
            this.getView().setModel(oModel);
        },
        onShowHello: function () {
            var oBundle = this.getView().getModel("i18n").getResourceBundle();
            var sRecipient = this.getView().getModel().getProperty("/recipient/name");
            MessageToast.show(oBundle.getText("helloMsg", [sRecipient]));
        }
    });
});

Y la vista que lo acompaña, sin una línea de lógica:

<mvc:View controllerName="logaligroup.SAPUI5.controller.App"
    xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc">
    <Button text="{i18n>showHelloButtonText}" press=".onShowHello"/>
    <Input value="{/recipient/name}" valueLiveUpdate="true" width="60%"/>
</mvc:View>

Tres decisiones que valen oro dentro de dos años:

  1. El texto del botón sale de {i18n>...}, no de un literal. Traducir es cambiar un .properties, no tocar la vista.
  2. El Input está vinculado a /recipient/name. Cambia el modelo y la UI se refresca sola, sin un solo setText.
  3. El press apunta a .onShowHello, una función del controlador. La vista no sabe qué hace ese handler, solo que existe.

El error que verás en todos los proyectos

Un App.controller.js de 800 líneas que formatea moneda, arma filtros, guarda estado y además navega. Funciona el día de la demo y es intocable el día del cambio. En cuanto necesites reutilizar ese formateo en otra vista, tendrás que copiarlo, y ahí empieza la deuda.

La separación MVC no es purismo académico. Es lo que permite que otro developer entre a tu app en seis meses y sepa, sin preguntarte, dónde vive cada cosa.

Cuando el modelo crece, sácalo a su propio fichero (model/Models.js). Cuando el formateo se repite, sácalo a un formateador. El controlador queda para lo único que le toca: reaccionar. En el próximo post entramos en el data binding, que es lo que hace que todo esto se sienta mágico.

¿Te ha resultado útil?

Comentarios

    Deja un comentario

    Responsable: Logali Tech. Finalidad: moderar y publicar tu comentario y, si dejas tu correo, avisarte. Derechos: acceso, rectificación y supresión en [email protected].