Le protocole OData

Avant de parler de OData il convient déjà de comprendre ce qu’est l’architecture REST. Comme cela est très bien résumé ici, http://www.croes.org/gerald/blog/qu-est-ce-que-rest/447/, REST est en gros un ensemble de conventions permettant de créer des services web basés sur le protocole HTTP. Par exemple, l’API de OpenWeatherMap utilisée précédemment via le web service Forecast est en fait une API REST dont la seule méthode disponible est GET.

OData dans tout ça est un protocole ouvert avec un ensemble de bonnes pratiques apportant une normalisation pour construire et consommer des APIs REST.

Si on prends par exemple le service http://services.odata.org/V4/(S(tbodsh53eaunnvmkizrjmuae))/TripPinServiceRW/People présenté sur OData.org en l’exécutant dans le navigateur, on obtiendra le résultat suivant :
2015-04-10_114155

Ce n’est pas super lisible mais on peut reconnaitre le format JSON. Ainsi pour rendre cela un peu plus clair on pourra dans ce cas encore utiliser un JSON Viewer pour rendre cela un peu plus parlant :

2015-04-10_152207

Publicités

Open UI5 : Création d’une application de prévisions météo

Pour faire suite au précédent article sur la consommation de web services JSON, nous allons maintenant développer une application de prévisions météo basée sur l’API de OpenWeatherMap. Celle-ci sera composée d’une zone de recherche (pour saisir la ville pour laquelle on souhaite récupérer les prévisions météo), d’un panel avec les prévisions du jour et d’une table contenant les prévisions sur une plage de 7 jours.

Aperçu du résultat final :
2015-04-09_145244

Commençons par créer un nouveau projet avec une vue main :
2015-04-09_114737

Modifiez le controller afin d’y ajouter une fonction de chargement des données à partir d’une ville passée en paramètre. Cette fonction sera appelée lors de la validation de la zone de recherche.

LoadWeather : function(ville){
//Instanciation du model JSON :
var jsonModel = new sap.ui.model.json.JSONModel();
//Construction de l’URL :
var apiUrl = « http://api.openweathermap.org/data/2.5/forecast/daily?q= » + ville + « &mode=json&units=metric&cnt=7 »;
//Chargement des donnees :
jsonModel.loadData(apiUrl);
//Assignation des donnees :
sap.ui.getCore().setModel(jsonModel);
//Mise a jour de l’image de la journee :
jsonModel.attachRequestCompleted(function() {
var icon = jsonModel.getProperty(« /list/0/weather/0/icon »);
var image = sap.ui.getCore().byId(« imageCurrent »);
image.setSrc(« http://openweathermap.org/img/w/ » + icon + « .png »);
});
}

On distingue ainsi :

Le chargement de données pour la ville passée en paramètre :
2015-04-09_120321

Assignation du modèle :
2015-04-09_120729

Actions à effectuer une fois les données complètement chargées (mise à jour de l’icone de la prévision du jour) :
2015-04-09_120809

Modifier ensuite la vue (fonction createContent) comme suit :

createContent : function(oController) {
//Barre de recherche :
var oSearch = new sap.ui.commons.SearchField(« simpleSearch », {
enableListSuggest: false,
search: function(oEvent){
oController.LoadWeather(oEvent.getParameter(« query »)); //Fonction a appeler
}});

//Table des previsions a 7 jours :
var weatherTable = new sap.ui.table.Table({
title : « Previsions a 7 jours »,
rows : {
path : « /list »,
sorter : new sap.ui.model.Sorter(« dt »)
},
visibleRowCount:7
});

//Colonne Jour :
weatherTable.addColumn(new sap.ui.table.Column({
label : new sap.ui.commons.Label({text : « Jour »}),
template: new sap.ui.commons.TextView({ text: {
parts: [
{path: « dt », type: new sap.ui.model.type.String()} ],
//Formatage de la date au format JJ/MM/YYYY
formatter: function(dt){
var date = new Date(dt*1000); //dt est un timestamp
var dd = date.getDate();
var mm = date.getMonth()+1; //Janvier = 0
var yyyy = date.getFullYear();

if(dd<10){
dd=‘0’+dd;
}
if(mm<10){
mm=‘0’+mm;
}

return dd+‘/’+mm+‘/’+yyyy;
}
}})
}));

//Colonne Temps (icone) :
weatherTable.addColumn(new sap.ui.table.Column({
label : new sap.ui.commons.Label({text : « Temps »}),
template: new sap.ui.commons.Image().bindProperty(« src », {
parts: [
{path: « weather/0/icon »} ],
//Formatage de l’url de l’icone a charger :
formatter: function(icon){
return « http://openweathermap.org/img/w/ &raquo; + icon + « .png »;
}})}));

//Colonne Observations :
weatherTable.addColumn(new sap.ui.table.Column({
label : new sap.ui.commons.Label({text : « Observation »}),
template: new sap.ui.commons.TextView({ text: « {weather/0/description} »})}));

//Colonne Temperature moyenne :
weatherTable.addColumn(new sap.ui.table.Column({
label : new sap.ui.commons.Label({text : « Temperature moyenne »}),
template: new sap.ui.commons.TextView({ text: {
parts: [
{path: « temp/day », type: new sap.ui.model.type.String()} ],
formatter: function(day){

return day + « \u00b0 » ;
}
}})
}));

//Colonne Temperature minimum :
weatherTable.addColumn(new sap.ui.table.Column({
label : new sap.ui.commons.Label({text : « Temperature min »}),
template: new sap.ui.commons.TextView({ text: {
parts: [
{path: « temp/min », type: new sap.ui.model.type.String()} ],
formatter: function(min){

return min + « \u00b0 » ;
}
}})
}));

//Colonne Temperature max :
weatherTable.addColumn(new sap.ui.table.Column({
label : new sap.ui.commons.Label({text : « Temperature max »}),
template: new sap.ui.commons.TextView({ text: {
parts: [
{path: « temp/max », type: new sap.ui.model.type.String()} ],
formatter: function(max){

return max + « \u00b0 » ;
}
}})
}));

//Colonne Vent :
weatherTable.addColumn(new sap.ui.table.Column({
label : new sap.ui.commons.Label({text : « Vent »}),
template: new sap.ui.commons.TextView({ text: {
parts: [
{path: « speed »} ],
formatter: function(speed){
return ((speed * 3.6).toFixed(2)) +  » Km/h »;
}
}})
}));

//Label de la barre de recherche :
var oLbl = new sap.ui.commons.Label(« search »);
oLbl.setLabelFor(oSearch);
oLbl.setText(« Ville »);
//Current weather panel :
var oImage = new sap.ui.commons.Image(« imageCurrent »);
var oPanelCurrent = new sap.ui.commons.Panel(« panelcurrent », {title:new sap.ui.core.Title(« title1 », {text:« Previsions du jour »})});
var oLayout01 = new sap.ui.commons.layout.MatrixLayout(« layout01 »);
oLayout01.createRow(oImage);
var oLayout02 = new sap.ui.commons.layout.MatrixLayout(« layout02 »);
oLayout02.createRow(« Ville : « , « {/city/name} », « {/city/country} » );
oLayout02.createRow(« Observation : « , « {/list/0/weather/0/description} » );
oLayout02.createRow(« Temp. moyenne : « , « {/list/0/temp/day} » );
oLayout02.createRow(« Temp. min : « , « {/list/0/temp/min} » );
oLayout02.createRow(« Temp. max : « , « {/list/0/temp/max} » );
var oLayout00 = new sap.ui.commons.layout.MatrixLayout(« layout00 »);
oLayout00.setWidth(« 400px »);
oLayout00.setWidths(« 40px »,« 300px »);
oLayout00.createRow(oLayout01, oLayout02);
oPanelCurrent.addContent(oLayout00);
//Barre de recherche et Current weather panel :
var oCell1 = new sap.ui.commons.layout.MatrixLayoutCell;
oCell1.addContent(oLbl);
oCell1.setVAlign(sap.ui.commons.layout.VAlign.Top);
var oCell2 = new sap.ui.commons.layout.MatrixLayoutCell;
oCell2.addContent(oSearch);
oCell2.setVAlign(sap.ui.commons.layout.VAlign.Top);
var layout = new sap.ui.commons.layout.MatrixLayout(« layout »);
layout.setWidth(« 800px »);
layout.setWidths(« 25px »,« 70px »,« 200px »);
layout.createRow(oCell1, oCell2, oPanelCurrent);
//Placement de tous les elements :
var oPanel = new sap.ui.commons.Panel(« panel », {title:new sap.ui.core.Title(« title », {text:« UI5 Live Meteo »})});
oPanel.addContent(layout);
oPanel.addContent(new sap.ui.commons.HorizontalDivider());
oPanel.addContent(weatherTable);
oPanel.placeAt(‘content’);
}


Voilà, notre application météo est développée 😉 :

2015-04-09_145244

Open UI5 : Consommation de web service JSON

Dans les exemples précédents, nous avons utilisé des modèles de données basés sur des données JSON écrites directement en dures dans le code. C’est sympa pour les exemples et pour comprendre comment ça marche, mais aurez compris que ce n’est évidemment pas la finalité 😉

Un web service c’est en gros, une url avec tout plein de paramètres (c’est mieux pour préciser ce que l’on souhaite récupérer ;-)) qui retourne les données correspondantes à notre requête dans un certain format (généralement XML ou JSON).

Admettons que vous souhaitiez développer une application qui affichera les prévisions météo d’une ville donnée, vous pourrez alors vous tourner vers le site OpenWeatherMap qui met à disposition une API répondant parfaitement à ce besoin.

Vous voulez par exemple récupérer les prévisions météo sur 7 jours, vous pouvez pour cela utiliser l’API avec l’url suivante :  api.openweathermap.org/data/2.5/forecast/daily?q=London&mode=xml&units=metric&cnt=7.

Ainsi on retrouve dans cette url :
– La ville (q) : ici « London »
– Le type de données à retourner (mode) : ici « XML »
– L’unité de mesure (units) : ici « metric »
– Le nombre de jours (cnt) : ici « 7 »

Vous pouvez charger cette url directement dans votre navigateur préféré, vous devriez alors obtenir quelque chose comme cela :
2015-04-09_105736

On peut ainsi voir les prévisions météo sur 7 jours pour la ville de Londres dans un format XML.

De même en demandant du format JSON (en spécifiant simplement mode=json au lieu de mode=xml) :
2015-04-09_110028

Bon comme ça c’est moins compréhensible, mais pas de panique notre ami Google regorge de JSON Viewer, par exemple http://jsonviewer.stack.hu/. Collez ainsi la chaîne JSON obtenue et cliquez sur Viewer :
2015-04-09_110510

Vous devriez obtenir cela (tout de suite c’est plus clair) :
2015-04-09_110816

Dans UI5, c’est presque comme ce que l’on a pu voir précédemment. En effet, à la place d’assigner les données en dures via la méthode sap.ui.model.json.JSONModel.setData(<JSON en dur>), on utilisera la méthode sap.ui.model.json.JSONModel.loadData(<url API>).

Open UI5 : Tables en-tête et détails

Nous allons maintenant reprendre le projet « CalculatedFields » créé précédemment, que nous allons faire évoluer afin d’ajouter en table d’en-tête contenant la liste des sports. Dès lors que l’utilisateur sélectionne un sport, la table de détails (liste des sportifs) sera filtrée avec les sportifs correspondants au sport sélectionné.

Pour ce faire il conviendra de créer une nouvelle table (contenant la liste des sports donc) qui filtrera la seconde table (liste des sportifs) via la méthode attachRowSelectionChange.

Adapter la méthode createContent comme suit pour répondre à ce nouveau besoin :


createContent : function(oController) {
//Donnees de la table :
var tableData = {
//Les sports :
« sports » : [
{« sport »:« Tous »},
{« sport »:« Athletisme »},
{« sport »:« Badminton »},
{« sport »:« Basketball »},
{« sport »:« Boxe »},
{« sport »:« Tennis »},
],
//Les sportifs :
« data » : [
{« nom »:« Bolt »,« prenom »:« Usain »,« discipline »:« Athletisme »},
{« nom »:« Jordan »,« prenom »:« Michael »,« discipline »:« Basketball »},
{« nom »:« Blake »,« prenom »:« Yohan »,« discipline »:« Athletisme »},
{« nom »:« Bryant »,« prenom »:« Kobe »,« discipline »:« Basketball »},
{« nom »:« Johnson »,« prenom »:« Magic »,« discipline »:« Basketball »},
{« nom »:« Tyson »,« prenom »:« Mike »,« discipline »:« Boxe »},
{« nom »:« Kournikova »,« prenom »:« Anna »,« discipline »:« Tennis« },
{« nom »:« Holyfield »,« prenom »:« Evander »,« discipline »:« Boxe »},
{« nom »:« Lee »,« prenom »:« Chong Wei »,« discipline »:« Badminton »}
]};

//Creation de l’instance du model JSON :
var oModel = new sap.ui.model.json.JSONModel();
var oPanel = new sap.m.Panel(« panel »);
var oPanel1 = new sap.m.Panel(« panel1 », {headerText:« Les sports »});
var oPanel2 = new sap.m.Panel(« panel2 », {headerText:« Les sportifs »});

//Donnees du model :
oModel.setData(tableData);

//Creation de la table :
var oTableSports = new sap.ui.table.Table({
width: « 100% »,
columns: [
//Colonne Sport :
new sap.ui.table.Column({
label:new sap.ui.commons.Label({ text : « Sport »}),
template: new sap.ui.commons.TextView({ text: « {sport} »}),
})],
visibleRowCountMode: sap.ui.table.VisibleRowCountMode.Fixed,
visibleRowCount:oModel.getData().sports.length,
});

//Model de la table de sports :
oTableSports.setModel(oModel);
//Binding de la table de sports :
oTableSports.bindRows(« /sports »);
//Ajout de la table au Panel 1 :
oPanel1.addContent(oTableSports);

//Creation de la table :
var oTable = new sap.ui.table.Table({
width: « 100% »,
columns: [
//Colonne Nom :
new sap.ui.table.Column({
label:new sap.ui.commons.Label({ text : « Nom »}),
template: new sap.ui.commons.TextView({ text: « {nom} »}),
}),
//Colonne Prenom :
new sap.ui.table.Column({
label:new sap.ui.commons.Label({ text : « Prenom »}),
template: new sap.ui.commons.TextView({ text: « {prenom} »}),
}),
//Colonne discipline :
new sap.ui.table.Column({
label:new sap.ui.commons.Label({ text : « Discipline »}),
template: new sap.ui.commons.TextView({ text: « {discipline} »}),
}),
//Colonne Description :
new sap.ui.table.Column({
label:new sap.ui.commons.Label({ text : « Description »}),
template: new sap.ui.commons.TextView({ text: {
parts: [
{path: « nom », type: new sap.ui.model.type.String()},
{path: « prenom », type: new sap.ui.model.type.String()},
{path: « discipline », type: new sap.ui.model.type.String()} ],
formatter: function(nom, prenom,discipline){
if( discipline != null){
if( discipline.charAt(0) == « A »){
return prenom +  » «  + nom +  » est un champion d' » + discipline;
}
else{
return prenom +  » «  + nom +  » est un champion de «  + discipline;
}
}
}
}}),
}),
],
visibleRowCountMode: sap.ui.table.VisibleRowCountMode.Fixed,
visibleRowCount:oModel.getData().data.length,
});

//Model de la table de sportifs :
oTable.setModel(oModel);
//Binding de la table de sportifs :
oTable.bindRows(« /data »);
//Ajout de la table au Panel 2 :
oPanel2.addContent(oTable);

//Ajout du Panel 1 au Panel global :
oPanel.addContent(oPanel1);
//Ajout du Panel 2 au Panel global :
oPanel.addContent(oPanel2);

//Evenement selection ligne :
oTableSports.attachRowSelectionChange(function(oEvent){
//Recuperation du contexte :
var selectedRowContext = oEvent.getParameter(« rowContext »);
//Recuperation du sport selectionne :
var selectedSport = oModel.getProperty(« sport », selectedRowContext);
//Binding sur table des sportifs :
var sportifsBinding = oTable.getBinding();
if (selectedSport == « Tous »){
//Application du filtre :
sportifsBinding.filter(null);
}
else{
//Filtre sur le sport :
var oFilter = new sap.ui.model.Filter(« discipline », sap.ui.model.FilterOperator.EQ, selectedSport);
//Application du filtre :
sportifsBinding.filter(oFilter);
}
});

return new sap.m.Page({
title: « Calculated fields Demo »,
content: [
oPanel
]
});
}


A la fin vous devriez obtenir cela :
2015-04-07_185038

2015-04-07_185219

2015-04-07_185314

Open UI5 : Les champs calculés

Les champs calculés permettent le binding de plusieurs propriétés d’un ou plusieurs models à une seule et même propriété d’un contrôle. On pourra ainsi, par exemple, binder la valeur d’un contrôle à une propriété « prénom » d’un model et à une propriété « nom » d’un autre model.

Associé à ce que l’on appelle un formatter, on pourra ainsi définir la façon dont les différentes propriétés seront traitées et assignées à la valeur du contrôle (via par exemple une concaténation).

Nous allons pour cet exemple afficher une table de sportifs affichant pour chacun d’entre eux : son nom, son prénom, et un intitulé du type « <prénom> <nom> est un champion de <discipline> ».

Pour ce faire, commençons par créer un nouveau projet, « CalculatedFields » par exemple (de type mobile, pour changer) :
2015-04-07_163730

Alimenter la méthode createContent comme suit pour créer la table basée sur le model JSon correspondant à notre liste de sportifs (le champ calculé correspondant à la dernière colonne, « description ») :


createContent : function(oController) {
//Donnees de la table :
var tableData = { « data » : [
{« nom »:« Bolt »,« prenom »:« Usain »,« discipline »:« Athletisme »},
{« nom »:« Jordan »,« prenom »:« Michael »,« discipline »:« Basketball »},
{« nom »:« Tyson »,« prenom »:« Mike »,« discipline »:« Boxe »},
{« nom »:« Kournikova »,« prenom »:« Anna »,« discipline »:« Tennis »},
{« nom »:« Lee »,« prenom »:« Chong Wei »,« discipline »:« Badminton »}
]};

//Creation de l’instance du model JSON :
var oModel = new sap.ui.model.json.JSONModel();

oModel.setData(tableData);

//Creation de la table :
var oTable = new sap.ui.table.Table({
width: « 100% »,
columns: [
//Colonne Nom :
new sap.ui.table.Column({
label:new sap.ui.commons.Label({ text : « Nom »}),
template: new sap.ui.commons.TextView({ text: « {nom} »}),
}),
//Colonne Prenom :
new sap.ui.table.Column({
label:new sap.ui.commons.Label({ text : « Prenom »}),
template: new sap.ui.commons.TextView({ text: « {prenom} »}),
}),
//Colonne discipline :
new sap.ui.table.Column({
label:new sap.ui.commons.Label({ text : « Discipline »}),
template: new sap.ui.commons.TextView({ text: « {discipline} »}),
}),
//Colonne Description :
new sap.ui.table.Column({
label:new sap.ui.commons.Label({ text : « Description »}),
template: new sap.ui.commons.TextView({ text: {
parts: [
{path: « nom », type: new sap.ui.model.type.String()},
{path: « prenom », type: new sap.ui.model.type.String()},
{path: « discipline », type: new sap.ui.model.type.String()} ],
formatter: function(nom, prenom,discipline){
if( discipline != null){
if( discipline.charAt(0) == « A »){
return prenom +  » «  nom +  » est un champion d' » + discipline;
}
else{
return prenom +  » «  + nom +  » est un champion de «  + discipline;
}
}
}
}}),
}),
],
visibleRowCountMode: sap.ui.table.VisibleRowCountMode.Fixed,
visibleRowCount:oModel.getData().data.length,
});

oTable.setModel(oModel);
oTable.bindRows(« /data »);

return new sap.m.Page({
title: « Calculated fields Demo »,
content: [
oTable
]
});
}


Ce qui donne le résultat suivant :

2015-04-07_165459

OpenUI5 : Tris et Filtres

Il est possible de trier et filtrer les données d’un modèle via les méthodes Sorter (sap.ui.model.Sorter) et Filter (sap.ui.model.Filter).

Pour cet exemple nous allons créer deux ComboBox, la première permettant, au choix, de trier ou filtrer les données de la seconde :
Capture d’écran 2015-04-03 à 00.07.39

Pour ce faire nous allons créer une fonction « sortFilter » permettant d’appliquer les tris/filtres et qui sera appelée par la méthode sap.m.ComboBox.attachSelectionChange() :


sortFilter : function (oEvent) {
//Recuperation de la fonction :
var fonction = oEvent.oSource.getSelectedItem().getBindingContext(« ModelOptions »).getProperty(« id »);
//Recuperation du binding :
var oBinding = sap.ui.getCore().byId(« dataVal »).getBinding(« items »);
//Selon la fonction :
switch(fonction){
//Tri par prenom :
case « sortPrenom »:
//Reinitialisation du filtre :
oBinding.filter(null);
//Tri par prenom :
oBinding.sort(new sap.ui.model.Sorter(« prenom », false));
break;
//Tri par nom :
case « sortNom »:
//Reinitialisation du filtre :
oBinding.filter(null);
//Tri par nom :
oBinding.sort(new sap.ui.model.Sorter(« nom », false));
break;
//Tri par parent :
case « filterParent »:
//Filtre par parent :
oBinding.filter(new sap.ui.model.Filter(« fonction », sap.ui.model.FilterOperator.EQ, « parent »));
break;
//Tri par enfant :
case « filterEnfant »:
//Filtre par enfant :
oBinding.filter(new sap.ui.model.Filter(« fonction », sap.ui.model.FilterOperator.EQ, « enfant »));
break;
}
},

createContent : function(oController) {
//****************** DECLARATION DES VARIABLES *********************
//JSon data – Liste des options :
var optionList = { « selection »:« Choose an option »« options »: [
    { « id »:« sortPrenom », « text »:« Trier par prenom »},
    { « id »:« sortNom », « text »:« Trier par nom »},
    { « id »:« filterParent », « text »:« Filtrer par parent »},
    { « id »:« filterEnfant », « text »:« Filtrer par enfant »},
    ]};
//JSon data – Liste des personnages :
var dataList = { « data »: [
{« id »: « hsimpson », « nom »: « Simpson », « prenom »: « Homer »,
« sexe »:« masculin », « fonction »:« parent »,   « text »: « Homer Simpson »},
{« id »: « msimpson », « nom »: « Simpson », « prenom »: « Marge »,
« sexe »:« feminin », « fonction »:« parent », « text »: « Marge Simpson »},
{« id »: « bsimpson », « nom »: « Simpson », « prenom »: « Bart »,
« sexe »:« masculin », « fonction »:« enfant », « text »: « Bart Simpson »},
{« id »: « lsimpson », « nom »: « Simpson », « prenom »: « Lisa »,
« sexe »:« feminin », « fonction »:« enfant », « text »: « Lisa Simpson »},
{« id »: « msimpson2 », « nom »: « Simpson », « prenom »: « Maggie »,
« sexe »:« feminin », « fonction »:« enfant », « text »: « Maggie Simpson »}
]};

//Creation des instances de models :
var oModelOptions = new sap.ui.model.json.JSONModel();
var oModelData = new sap.ui.model.json.JSONModel();
//Assignation des donnees au model – Options :
oModelOptions.setData(optionList);
//Assignation des donnees au model – Data :
oModelData.setData(dataList);
//Assignation du model options :
sap.ui.getCore().setModel(oModelOptions, « ModelOptions »);
//Assignation du model data :
sap.ui.getCore().setModel(oModelData, « ModelData »);
//Panel :
var oPanel = new sap.m.Panel(« panel »);
//Layout :
var oLayout = new sap.ui.commons.layout.MatrixLayout(« layout »);
//Label Options :
var oOptionsLbl = new sap.m.Label(« optionsLbl », {text:« Options », labelFor:« oOptionsVal »});
//Options :
var oOptionsVal = new sap.m.ComboBox(« optionsVal »);
//Label Personnages :
var oDataLbl = new sap.m.Label(« dataLbl », {text:« Personnages », labelFor:« oDataVal »});
//Personnages :
var oDataVal = new sap.m.ComboBox(« dataVal »);
//Ajout des options dans le Select :
//oOptionsVal.bindAggregation(« items », {path: »ModelOptions>/options », template: new sap.ui.core.ListItem(« options », {text: « {ModelOptions>text} »,  key: « {ModelOptions>id} » })});
oOptionsVal.bindItems({path:« ModelOptions>/options », template:new sap.ui.core.ListItem(« options », {text: « {ModelOptions>text} »,  key: « {ModelOptions>id} » })});
oOptionsVal.bindValue(« ModelOptions>/selection »);
oOptionsVal.attachSelectionChange(this.sortFilter);
//Ajout des personnages dans le Select :
//oDataVal.bindAggregation(« items », {path: »ModelData>/data », template: new sap.ui.core.ListItem(« data », {text: « {ModelData>text} »,  key: « {ModelData>id} » })});
oDataVal.bindItems({path:« ModelData>/data », template:new sap.ui.core.ListItem(« data », {text: « {ModelData>text} »,  key: « {ModelData>id} » })});
//Longueur totale du layout :
oLayout.setWidth(« 100% »);
//Longueur de chaque colonne du layout :
oLayout.setWidths(« 30% »,« 70% »);
//Creation de la ligne dans le layout :
oLayout.createRow(oOptionsLbl,oOptionsVal);
//Ajout des personnes dans le select :
oLayout.createRow(oDataLbl,oDataVal);
//Ajout du layout au panel :
oPanel.addContent(oLayout);
//Ajout du panel au layout :
oPanel.placeAt(« content »);
}


A la fin vous devriez avoir le résultat suivant :
Capture d’écran 2015-04-03 à 00.07.39

Capture d’écran 2015-04-03 à 00.17.53

Capture d’écran 2015-04-03 à 00.17.17

OpenUI5 : Type de donnée personnalisé

Si les types de donnée standards ne vous conviennent pas, vous avez la possibilité de définir vos propres types de donnée via la méthode « sap.ui.model.SimpleType.extend ».

Ainsi, reprenez le projet SimpleApplication que nous allons modifier pour ajouter un champ E-Mail implémentant un contrôle de validité de l’adresse mail. Pour ce faire, procédez de la façon suivante :


openAlert : function (oEvent) {
sap.ui.getCore().byId(« prenomVal »).setValue(
oEvent.oSource.getSelectedItem().getBindingContext().getProperty(‘prenom’));

sap.ui.getCore().byId(« nomVal »).setValue(
oEvent.oSource.getSelectedItem().getBindingContext().getProperty(‘nom’));
},

createContent : function(oController) {
//****************** DECLARATION DES VARIABLES *********************
//Creation d’un nouveau type de donnees « E-mail » avec controle du format :
sap.ui.model.SimpleType.extend(« sap.test.eMail », {
formatValue: function(oValue){
return oValue;
},
parseValue: function(oValue){
return oValue;
},
validateValue: function(oValue){
//Expression reguliere de controle du format d’une adresse e-mail :
var mailregex = /^\w+[\w-\.]*\@\w+((-\w+)|(\w*))\.[a-z]{2,3}$/;
//Controle de l’adresse e-mail :
if (!oValue.match(mailregex)) {
//L’adresse e-mail n’est pas valide, on leve une exception :
throw new sap.ui.model.ValidateException(« L’adresse e-mail n’est pas valide »);
}
}
});

//Attachement evenement erreur validation :
sap.ui.getCore().attachValidationError(function(ex){
//On met le champ en erreur :
ex.getParameter(« element »).setValueState(sap.ui.core.ValueState.Error);
// On assigne un message d’erreur au champ :
ex.getParameter(« element »).setValueStateText(ex.getParameter(« exception »).message);
});

//Attachement evenement succes validation :
sap.ui.getCore().attachValidationSuccess(function(evt){
//On met le champ en succes :
evt.getParameter(« element »).setValueState(sap.ui.core.ValueState.Success);
});

//JSon data – Liste des utilisateurs :
var dataList = { « email »:«  », « data »: [
{« id »: « hsimpson », « nom »: « Simpson », « prenom »: « Homer », « text »: « Homer Simpson »},
{« id »: « msimpson », « nom »: « Simpson », « prenom »: « Marge », « text »: « Marge Simpson »},
{« id »: « bsimpson », « nom »: « Simpson », « prenom »: « Bart », « text »: « Bart Simpson »},
{« id »: « lsimpson », « nom »: « Simpson », « prenom »: « Lisa », « text »: « Lisa Simpson »},
{« id »: « msimpson2 », « nom »: « Simpson », « prenom »: « Maggie », « text »: « Maggie Simpson »}
]};

//Creation de l’instance du modele JSON :
var oModel = new sap.ui.model.json.JSONModel();

//Assignation des donnees au modele :
oModel.setData(dataList);

//Panel :
var oPanel = new sap.ui.commons.Panel(« panel »);
//Titre du Panel :
var oTitle = new sap.ui.core.Title;
//Layout :
var oLayout = new sap.ui.commons.layout.MatrixLayout(« layout »);
//Cellule :
var oCell = new sap.ui.commons.layout.MatrixLayoutCell;
//Label prenom :
var oPrenom = new sap.ui.commons.Label(« prenom »);
//Label nom :
var oNom = new sap.ui.commons.Label(« nom »);
//Text field prenom :
var oPrenomVal = new sap.ui.commons.TextField(« prenomVal »);
//Text field nom :
var oNomVal = new sap.ui.commons.TextField(« nomVal »);
//Text Or pick a username :
var oPickUserName = new sap.ui.commons.Label(« Pick »);
//Label e-mail :
var oMail = new sap.ui.commons.Label (« email »);
//Text field e-mail :
var oMailVal = new sap.ui.commons.TextField(« eMail », { //ou sap.m.Input
placeholder:« Saisir une adresse e-mail valide »,
width:« 400px »,
value: {
path: « /email »,
type: new sap.test.eMail(), //Type e-mail créé plus haut
}});
//Bouton submit :
var oButton = new sap.ui.commons.Button;
//Liste d’utilisateurs :
var oSelect = new sap.m.Select(« listSelect »);
//****************************************************************
//Assignation du modele au panel :
oPanel.setModel(oModel);
//Titre du panel :
oPanel.setTitle(oTitle);

//Texte du titre :
oTitle.setText(« User details »);

//Layout fixe :
oLayout.setLayoutFixed(true);
//Longueur totale du layout :
oLayout.setWidth(« 550px »);
//Longueur de chaque colonne du layout :
oLayout.setWidths(« 150px »,« 400px »);

//Texte du label prenom :
oPrenom.setText(« Prenom »);
//Label associe au text field prenom :
oPrenom.setLabelFor(oPrenomVal);

//Creation de la ligne dans le layout :
oLayout.createRow(oPrenom,oPrenomVal);

//Texte du label nom :
oNom.setText(« Nom »);
//Label associe au text field nom :
oNom.setLabelFor(oNom);

//Creation de la ligne dans le layout :
oLayout.createRow(oNom,oNomVal);

//Ajout des utilisateurs dans le Select :
oSelect.bindAggregation(« items », « /data », new sap.ui.core.Item(« user », {text: « {text} », key: « {id} » }));
//Methode appelee lors d’un changement du Select :
oSelect.attachChange(this.openAlert);
//Texte du label du Select :
oPickUserName.setText(« Or pick a user name »);
//Creation du select :
oLayout.createRow(oPickUserName, oSelect);
//Texte du label du Select :
oMail.setText(« E-mail »);
//Creation du select :
oLayout.createRow(oMail, oMailVal);

//Texte du bouton :
oButton.setText(« Submit »);
//ColSpan de la cellule :
oCell.setColSpan(2);
//Alignement de la cellule :
oCell.setHAlign(« End »);
//Ajout du bouton dans la cellule :
oCell.addContent(oButton);

//Creation de la ligne dans le layout :
oLayout.createRow(oCell);

//Ajout du layout au panel :
oPanel.addContent(oLayout);

//Ajout du panel au layout :
oPanel.placeAt(« content »);
}


Testez, votre application, vous devriez obtenir quelque chose comme ça :

2015-04-02_145207

Saisir une adresse e-mail au format erroné et validez. Celle-ci se retrouve en erreur :
2015-04-02_145405

Modifiez l’adresse dans un format correct et cliquez à nouveau. Celle-ci se retrouve en succès :
2015-04-02_145547

Il est également possible d’associer un message d’erreur à la zone en erreur, mais pour cela il est nécessaire de remplacer le type d’objet correspondant à l’adresse e-mail (sap.m.Input au lieu de sap.ui.commons.TextField). En effet, pour ce faire il faut utiliser la propriété setValueStateText qui n’existe pas pour le contrôle sap.ui.commons.TextField :


//Text field e-mail :
var oMailVal = new sap.m.Input(« eMail », { //ou sap.ui.commons.TextField
placeholder:« Saisir une adresse e-mail valide »,
width:« 400px »,
value: {
path: « /email »,
type: new sap.test.eMail(), //Type e-mail créé plus haut
}});


Ce qui devrait maintenant vous donner ceci :
2015-04-02_150440

2015-04-02_150500

OpenUI5 : Type Date

Nous allons maintenant reprendre l’application précédente et modifier le titre du Panel pour y afficher la date du jour. Pour cela nous allons typer la propriété text en Date.

1 – Modification de la méthode createContent comme suit :

createContent : function(oController) {
//****************** DECLARATION DES VARIABLES *********************
//JSon data – Liste des utilisateurs 1 :
var dataList1 = { « data »: [
{« id »: « hsimpson », « nom »: « Simpson », « prenom »: « Homer », « text »: « Homer Simpson »},
{« id »: « msimpson », « nom »: « Simpson », « prenom »: « Marge », « text »: « Marge Simpson »},
]};

//JSon data – Liste des utilisateurs 2 :
var dataList2 = { « data »: [
{« id »: « bsimpson », « nom »: « Simpson », « prenom »: « Bart », « text »: « Bart Simpson »},
{« id »: « lsimpson », « nom »: « Simpson », « prenom »: « Lisa », « text »: « Lisa Simpson »},
{« id »: « msimpson2 », « nom »: « Simpson », « prenom »: « Maggie », « text »: « Maggie Simpson »}
]};

//Creation de l’instance du model JSON :
var oModel = new sap.ui.model.json.JSONModel();

//Assignation des donnees au modele :
oModel.setData(
{date: new Date()}
);

//Creation de l’instance du modele JSON 1 :
var oModel1 = new sap.ui.model.json.JSONModel();

//Creation de l’instance du modele JSON 2 :
var oModel2 = new sap.ui.model.json.JSONModel();

//Assignation des donnees au modele 1 :
oModel1.setData(dataList1);

//Assignation des donnees au modele 2 :
oModel2.setData(dataList2);

//Assignation du modèle 1 :
sap.ui.getCore().setModel(oModel1, « Model1 »);
//Assignation du modèle 2 :
sap.ui.getCore().setModel(oModel2, « Model2 »);
//Assignation du modele :
sap.ui.getCore().setModel(oModel, « Model »);
//Panel :
var oPanel = new sap.ui.commons.Panel(« Panel »);
//Titre du Panel :
var oTitle = new sap.ui.core.Title(« Title »);
//Layout :
var oLayout = new sap.ui.commons.layout.MatrixLayout(« layout »);
//Text Pick a username :
var oPickUserName1 = new sap.ui.commons.Label(« Pick1 »);
//Text Pick a username :
var oPickUserName2 = new sap.ui.commons.Label(« Pick2 »);
//Liste d’utilisateurs 1 :
var oSelect1 = new sap.m.Select(« listSelect1 »);
//Liste d’utilisateurs 2 :
var oSelect2 = new sap.m.Select(« listSelect2 »);

//****************************************************************
//Texte du titre du panel :
oTitle.bindProperty(« text », {path:« Model>/date », type: new sap.ui.model.type.Date({pattern:« dd.MM.YYYY »})});
//Assignation du titre du panel :
oPanel.setTitle(oTitle);

//Layout fixe :
oLayout.setLayoutFixed(true);
//Longueur totale du layout :
oLayout.setWidth(« 700px »);
//Longueur de chaque colonne du layout :
oLayout.setWidths(« 150px »,« 200px »,« 150px »,« 200px »);

//Ajout des utilisateurs dans le Select :
oSelect1.bindAggregation(« items », « Model1>/data », new sap.ui.core.Item(« user1 », {text: « {Model1>text} », key: « {Model1>id} » }));
//Texte du label du Select :
oPickUserName1.setText(« Pick a user name »);
//Ajout des utilisateurs dans le Select :
oSelect2.bindAggregation(« items », « Model2>/data », new sap.ui.core.Item(« user2 », {text: « {Model2>text} », key: « {Model2>id} » }));
//Texte du label du Select :
oPickUserName2.setText(« Pick a user name »);
//Creation du select :
oLayout.createRow(oPickUserName1, oSelect1, oPickUserName2, oSelect2);

//Ajout du layout au panel :
oPanel.addContent(oLayout);
//Ajout du panel au layout :
oPanel.placeAt(« content »);
}

2 – Testez l’application :

2015-03-31_174708

OpenUI5 : Models multiples

Comme vu précédemment, les models permettent de contenir des sources de données et peuvent être mappés à différents contrôles. On distingue ainsi 3 types de models : JSONModel, XMLModel et ODataModel. Ceux-ci peuvent être assignés à un contrôle (un panel, un layout, une liste, une table, etc.) ou au Core.

Quelque soit l’élément, il est possible d’assigner plusieurs models, en prenant soin de préciser le nom du modèle.

Exemple :
sap.ui.getCore().setModel(oModel1, « Model1 »);
sap.ui.getCore().setModel(oModel2, « Model2 »);

Pour l’utilisation il faudra simplement utiliser la syntaxe suivante : « Model1>xxx » où « xxx » correspond à la source de données (par exemple « Model1>/data », à la place de « /data »).

1 – Créez un nouveau projet « MultipleModelsDemo » avec une vue « main » de type Javascript :
2015-03-31_160808

2 – méthode createContent :

createContent : function(oController) {
//****************** DECLARATION DES VARIABLES *********************
//JSon data – Liste des utilisateurs 1 :
var dataList1 = { « data »: [
{« id »: « hsimpson », « nom »: « Simpson », « prenom »: « Homer », « text »: « Homer Simpson »},
{« id »: « msimpson », « nom »: « Simpson », « prenom »: « Marge », « text »: « Marge Simpson »},
]};

//JSon data – Liste des utilisateurs 2 :
var dataList2 = { « data »: [
{« id »: « bsimpson », « nom »: « Simpson », « prenom »: « Bart », « text »: « Bart Simpson »},
{« id »: « lsimpson », « nom »: « Simpson », « prenom »: « Lisa », « text »: « Lisa Simpson »},
{« id »: « msimpson2 », « nom »: « Simpson », « prenom »: « Maggie », « text »: « Maggie Simpson »}
]};

//Creation de l’instance du modele JSON 1 :
var oModel1 = new sap.ui.model.json.JSONModel();

//Creation de l’instance du modele JSON 2 :
var oModel2 = new sap.ui.model.json.JSONModel();

//Assignation des donnees au modele 1 :
oModel1.setData(dataList1);

//Assignation des donnees au modele 2 :
oModel2.setData(dataList2);

//Assignation du modèle 1 :
sap.ui.getCore().setModel(oModel1, « Model1 »);
//Assignation du modèle 2 :
sap.ui.getCore().setModel(oModel2, « Model2 »);

//Panel :
var oPanel = new sap.ui.commons.Panel(« panel »);
//Titre du Panel :
var oTitle = new sap.ui.core.Title;
//Layout :
var oLayout = new sap.ui.commons.layout.MatrixLayout(« layout »);
//Text Pick a username :
var oPickUserName1 = new sap.ui.commons.Label(« Pick1 »);
//Text Pick a username :
var oPickUserName2 = new sap.ui.commons.Label(« Pick2 »);
//Liste d’utilisateurs 1 :
var oSelect1 = new sap.m.Select(« listSelect1 »);
//Liste d’utilisateurs 2 :
var oSelect2 = new sap.m.Select(« listSelect2 »);
//****************************************************************
//Titre du panel :
oPanel.setTitle(oTitle);

//Texte du titre :
oTitle.setText(« User details »);

//Layout fixe :
oLayout.setLayoutFixed(true);
//Longueur totale du layout :
oLayout.setWidth(« 700px »);
//Longueur de chaque colonne du layout :
oLayout.setWidths(« 150px »,« 200px »,« 150px »,« 200px »);

//Ajout des utilisateurs dans le Select :
oSelect1.bindAggregation(« items », « Model1>/data », new sap.ui.core.Item(« user1 », {text: « {Model1>text} », key: « {Model1>id} » }));
//Texte du label du Select :
oPickUserName1.setText(« Pick a user name »);
//Ajout des utilisateurs dans le Select :
oSelect2.bindAggregation(« items », « Model2>/data », new sap.ui.core.Item(« user2 », {text: « {Model2>text} », key: « {Model2>id} » }));
//Texte du label du Select :
oPickUserName2.setText(« Pick a user name »);
//Creation du select :
oLayout.createRow(oPickUserName1, oSelect1, oPickUserName2, oSelect2);

//Ajout du layout au panel :
oPanel.addContent(oLayout);
//Ajout du panel au layout :
oPanel.placeAt(« content »);
}

2015-03-31_161105

3 – Testez l’application :
2015-03-31_162103

2015-03-31_162118

OpenUI5 : Debug de la console Javascript

Vous venez de terminer de développer votre application et là vous vous rendez compte que cela ne fonctionne pas vraiment comme attendu (il manque la moitié des infos sur l’écran voire la totalité, des zones ne sont pas alimentées… bref rien ne va) ? Pas de panique ! La plupart du temps vous pourrez trouver tout seul votre erreur dans la console Javascript de votre navigateur.

Exemple sur Google Chrome :
2015-03-31_151714

1 – Reprenez l’exemple précédent et supprimez y par exemple l’utilisation de la librairie « sap.m » :
2015-03-31_110902

Vous devriez donc avoir ceci :
2015-03-31_152035

2 – En testant l’application, vous devriez avoir le résultat suivant :
2015-03-31_152149

L’écran apparaît vide.

3 – Pour savoir ce qu’il se passe, il va falloir accéder à la console Javascript (Ctrl+Maj+J sur Google Chrome) :
2015-03-31_151714

On peut voir l’erreur suivante (attention il vous faudra peut-être rafraîchir la page une fois la console Javascript ouverte pour voir l’erreur) :
2015-03-31_152525

En effet, la librairie « sap.m » n’étant plus inclus dans le projet, le contrôle « sap.m.select » n’a pas été trouvé.

4 – Si on le rajoute, l’application fonctionne à nouveau :
2015-03-31_110902

2015-03-31_112633