miércoles, 24 de mayo de 2017

SAP UI5 y oData: Asociaciones, navegación y expand (y III, usar en SAP UI5)

En capítulos anteriores...

Habíamos visto la teoría para intentar entender qué es eso de las asociaciones, las navegaciones y el expand. Para ello nos habíamos basado en un ejemplo, una aplicación friki para mostrar series de ciencia ficción y sus personajes, en plan Master and Detail.

Después, nos habíamos peleado con SAP para crear, mediante las transacciones SEGW y SE24, el servicio oData.

Ahora nos toca desarrollar la aplicación en SAP UI5, una de tipo Master-Detail que consuma el servicio creado en el paso anterior.


Pero vamos a ver varias formas de hacerlo, dónde y cómo podemos navegar y expandir la navegación. Tanto añadiendo código en la vista (como hace el Web IDE) como en el controller (por si queremos realizar algún tratamiento especial al resultado, más allá de recuperar los datos).

NOTA: Si la parte de crear el oData en ABAP os la saltasteis, podéis recurrir al servicio odata de Northwind. Por ejemplo, con la colección Regions y la navegación Territories, http://services.odata.org/Northwind/Northwind.svc/Regions?$expand=Territories&$format=json



Crear la aplicación en el Web IDE


La aplicación que nos tenemos que crear es de tipo Master-Detail. Si no sabes cómo crear este tipo de aplicación, puedes echarle un ojo a este post.

Nos creamos entonces la aplicación, elegimos el servicio oData y cuando llegamos a la zona de configuración de la plantilla, elegimos como colección principal Sagas.


Y un poquito más abajo es donde nos pide la navegación, que se utilizará para rellenar una tabla de datos cada vez que seleccionemos una saga en el maestro. Ahí indicamos LosPersonajes como propiedad.


Y al finalizar, ¡ya está! Nos ha funcionado sin haber hecho nada especial. Cada vez que seleccionemos en el Master una saga, en el Detail nos mostrará una tabla con sus personajes. Estamos hechos unos máquinas.

¡Si parece que sabemos lo que hacemos y todo!

¿Pero cómo consigue Web IDE enlazar la navegación?


Para saber cómo se enlaza la navegación, buscamos la tabla (<Table>) en la vista de detalle, Detail.view.xml e investigamos un poco.

Ahí encontraremos un atributo que pone items="{LosPersonajes}". Este atributo (que es una agregación) es el que va a invocar la navegación. Lo que hace es decir "en esta tabla tengo ciertos items -las filas- y las voy a pintar con lo que me venga en la navegación LosPersonajes, así que voy a invocarla". Después, en el bloque items que hay más adelante, ya especifico las propiedades de los personajes que voy a pintar (en nuestro ejemplo, el nombre y el id).

Éste es el código estándar. Yo sólo lo he retocado un poco para que se viese mejor.
Lo que está resaltado es la navegación LosPersonajes
y las propiedades que vamos a usar de dicha navegación, Nombre e Id.

¿Pero cómo sabe de qué entidad de Saga debe mostrar los personajes? Podemos revisar este post donde se explica el código generado de forma automática, pero voy a explicarlo rápidamente.

Cuando se pinta el detalle, LosPersonajes no vale nada, es una entidad vacía, así que la tabla puede venir inicialmente en blanco. Pero cuando el controlador (Detail.controller.js) enlaza la entidad seleccionada a la vista (busca el código this.getView().bindElement), entonces ya tenemos datos en la vista.

Por ejemplo, si hemos seleccionado como serie Firefly (mi favorita, dónde va a parar), en la vista se enlaza /Sagas('FIREFLY') y, por tanto, los items de la tabla realizarán la llamada /Sagas('FIREFLY')/LosPersonajes. ¡Caray, nuestra navegación!

Vamos a expandir


Queremos añadir una nueva opción en la tabla, el nombre de la saga de cada personaje. Sí, sí, lo sé, no tiene mucho sentido, porque cada personaje es de la saga que se ha seleccionado en el maestro, pero esto sólo tiene un objetivo práctico.

LaSaga era la navegación que llamaremos desde Personajes. Así que cambiamos la propiedad Id por la propiedad LaSaga/Nombre.


Esto, tal cual, no nos mostrará nada. Hemos enlazado el campo, pero no lo hemos expandido ni se hace la navegación de forma automática como ocurre con el items.

No vemos la saga de cada personaje. Prueba no superada :(

¿Cómo hacemos para obtenerlo? Podemos elegir hacerlo en dos sitios diferentes:

  • Podemos hacerlo en el controlador, en el lugar en el que enlazamos la entidad seleccionada con la vista. Buscamos el método bindElement, donde sObjectPath es la saga seleccionada (por ejemplo, /Sagas('FIREFLY'). ¿Os dije que era la que más me molaba?).

    Dentro del parámetro parameters, podemos añadir el parámetro expand sobre dicho sObjectPath. Como lo que estamos enlazando es una entidad de /Sagas, lo que tenemos que expandir es LosPersonajes y luego LaSaga, así que nos queda algo como:

    parameters: {expand: "LosPersonajes/LaSaga"}


  • Pero también podemos hacerlo en la vista. En lugar de hacer el expand donde hemos dicho antes, vamos a la tabla de la vista y modificamos el valor de items. Ahora ya tenemos varios parámetros que indicar, así que no nos vale con hacer items={LosPersonajes}, sino que tenemos que indicar el path que enlazamos y los parámetros adicionales, donde estará el expand. Nos quedará esto:

    items="{path: 'LosPersonajes', parameters : { 'expand' : 'LaSaga' }}"
    .


Con ambos modos, estaremos haciendo el expand tras seleccionar una nueva saga, y la tabla ya tendrá datos que mostrar correctamente.

¡Prueba superada!

Todo esto parece un jeroglífico, pero al final acaba teniendo su lógica y todo.

Tratar los datos del expand en el controlador


Vamos a imaginarnos un nuevo caso. Queremos recuperar los datos pero tenemos que hacerles algún tratamiento dentro del código, así que no nos vale con enlazarlo directamente a la vista. ¿Cómo hacemos ahí el expand?

Pues fácil, cuando hagamos el read del modelo de datos, simplemente le tenemos que añadir el parámetro urlParameters, donde indicamos que queremos hacer el expand, tal que así: 

urlParameters: { "$expand" : "LaNavegacionQueQueramos" }

Ahora veamos el ejemplo: Mostraremos una tabla con todos los personajes que tenemos en la base de datos, no sólo los de la saga elegida. Y entre los campos que vamos a mostrar, estará el nombre de la saga. Así que usaremos la colección /Personajes y expandiremos LaSaga.

Este código está al final del onInit

En este código, leemos la colección Personajes, le hacemos el expand para poder obtener el nombre de sus sagas, y asignamos dicho resultado a un nuevo modelo de datos llamado PJs. 

En oData (dentro de la función del success, que se ejecuta cuando se lee con éxito la entidad) tenemos todos los datos de la colección, incluido el expand. Si hubiésemos querido, podríamos haber recorrido ese parámetro en un bucle y obtener el nombre de la saga con oData.results[i].LaSaga.Nombre.

Y para mostrarlo, basta con ir a la vista de detalle y crear una nueva tabla, donde enlazamos el nuevo modelo de datos que hemos creado, PJs.


Con eso, ya tenemos una tabla debajo de la otra, y hemos aprendido bastante de asociaciones, navegaciones y expand. Y a mí me han entrado ganas de volver a ver ciertas series de televisión, ¿os imagináis cuáles?

En la tabla de arriba, tengo los personajes de la saga seleccionada.
En la tabla de abajo, tengo un listado con todos los personajes.





No hay comentarios:

Publicar un comentario