[SAPUI5] Load local JSON model directly from the manifest.json
#tipoftheday will be a series of blog post that I’m mirroring from my Medium account.
Before SAPUI5 1.30 you were forced to init your JSON model inside your Component.js like this:
sap.ui.define([
"sap/ui/core/UIComponent",
"sap/ui/model/json/JSONModel"
], function(UIComponent, JSONModel) {
"use strict";
return UIComponent.extend("com.openui5.example.Component", {
metadata: {
manifest: "json"
},
init: function() {
// call the base component's init function
UIComponent.prototype.init.apply(this, arguments);
//Create the model and load data from the local JSON file
var oModel = new JSONModel("./model/init_data.json");
oModel.setDefaultBindingMode("OneWay");
// set the device model
this.setModel(oModel, "init_data");
}
});
});
Why waste time and code when you can simply load it directly from the manifest.json?
I’ve created a stripped manifest that will show you only the interesting parts to copy/past.
{
"_version": "1.1.0",
"sap.app": {
"dataSources": {
"init_data_alias": {
"uri": "model/init_data.json",
"type": "JSON"
}
}
},
"sap.ui5": {
"_version": "1.1.0",
"models": {
"i18n": {
"type": "sap.ui.model.resource.ResourceModel",
"settings": {
"bundleName": "com.openui5.example.i18n.i18n"
}
},
"init_data": {
"type": "sap.ui.model.json.JSONModel",
"dataSource": "init_data_alias"
}
}
}
}
- Create an entry inside the sap.app dataSources with an alias name like “init_data_alias”. You must at least specify the uri of the source that can be a local path to the json file or an URL to the service. Also you can specify the type of the data (default oData)
- Create an entry inside the sap.ui5 models. The name used for the entry name will be the name of the model. Leave it alone if you want to replace the default component model. Now you just need to specify the type (in my case sap.ui.model.json.JSONModel) and which is the dataSource alias we used inside sap.app.dataSources
Pretty easy uh?
Hi Emanuele,
It was very helpful and nicely explained. Only question bothering me is if I have to add add source for OData I will do something like this
}
What will happen when I will add remote OData endpoints? Do I need to update manifest? can I add two data source for OData i.e for local and remote?
Hi @Nitin, here's a working example:
Could also please reformat your code in order to let other user read it properly?
Cheers, Emanuele.
Hi @Emanuele,
I followed your article and I gave an entry in the datasources with an alias name "airline_data_alias" as follows -
and gave a model definition as well -
But for some reason, I am not able to use the JSONModel when I use the alias inside the Controller -
I tried using -
var localModel = new sap.ui.model.json.JSONModel("airline_data");
It still didn't work.
It worked only when I gave the url to the JSON file -
var localModel = new sap.ui.model.json.JSONModel("model/airlineData.json");
Is there a way to avoid the usage of url ?
Regards,
Michael Paonam
I've not tested your code yet but I can see a typo inside your "dataSources" definition.
You typed airine_data_alias instead of airline_data_alias. You're missing an l 😉
How do you specify the mode of binding (OneWay/TwoWay) inside manifest file?
Hi Vishnu as far as I can see it is possible to do that.
This is the documentation about manifest.json (really poor). Take a look at the "models" section. You have to use the settings attribute that will pass all the object configuration to the ODataModel constructor.
I've not personally tested it but you can go with something like this:
Hi Ricci, Thank you for the reply. I have tried this but this is not setting up the model. By default, I could see the model is TwoWay in debugger. In manifest, i want to set it to OneWay, but not happening. Any other leads?
I know this is late. I have debugged the standard code and found out the following chain. Since the "binding type" is a part of sap.ui.model.Model, its constructor ignores settings from manifest.json:
The constructor doesn't accept any arguments and thus, the defaultBindingMode property is always TwoWay.
By the way, you should not use "settings" in manifest.json for JSONModel, because it isn't "settings", it is "bObserve" (new sap.ui.model.json.JSONModel(oData, bObserve)). The funny fact is that you cannot define "bObserve" in the "settings", because the manifest.json processing code is written for OData models only. JSON or other models are handled so-so.
I have to admit, that there is no way to work with two-way binding (or other properties) in manifest.json, if you do not use ODataModel. Some settings are propagated to ODataModel, but for other models everything is lost.
Hi Vladislav,
I find your reply very helpful. I've also noticed, that if I set some Model attribute in onInit event, it will be overwritten. Do you know the way to redefine Constructor of the Model?
Oh, I haven't noticed your question. Sorry.
Indeed, I do not know a better way to override the constructor rather than to inherit the class and implement your changes there.
I have two ideas 🙂
The first one is to use events from ComponentContainer, e.g. componentCreated or init and override the model properties there,
or the second one is to set the breakpoint in the default constructor and check via the stack from which part of the application lifecycle it is called. Maybe few lines down, you can change the required properties.
Emanuele,
Great post. Thank you for sharing. I do have a question though: What if I want to temporarily provide the app server (protocol, hostname, port) for the odata service while testing on my local machine? Is there a simple way to do that (other than hard-coding it with the uri in the manifest.json, then removing later before I deploy to the server)?
Thanks,
Michael Smith
At what point does the model become available ,
i downloaded the sample shop administration app from :
https://openui5nightly.hana.ondemand.com/#/demoapps
Sample app is:
https://openui5nightly.hana.ondemand.com/test-resources/sap/tnt/demokit/toolpageapp/webapp/index.html
in the App.controller.js i tried the following in the init() function
var oBundle = this.getModel("i18n").getResourceBundle();
However in the console it returns :
Cannot read property 'getResourceBundle' of undefined
Manifest does have :
and Component.js has
kind regards,
Garreth.
Hi Garreth,
as far as I can see Component and Controllers are loaded async and in parallel.
This means that it could happen that in the onInit of the main controller all models loaded from the manifest could still be undefined/null.
In the other hands, if your data binding is still done in the xml you should not have any problem because those bindings are refreshed when the data model is updated.
Hi Emanuele Ric,
I am getting a 404(Not Found) error. i followed the below steps.
2. defined the datasource under dataSources section
3. created a new json file in model folder with name "personData.json"
4. tried to access the model using
i dont get any error (like undefined) in accessing oPersonDataModel variable but i can not see any property that i have defined in personData.json file. The console shows error 404 (Not Found) for personData_alis.
Could you please help
Hi Narender, you can have a look at a demo code here (how to define model/data source in manifest JSON and how to use it inside your view/controller): https://github.com/StErMi/openui5-swissknife/tree/master/test/demo-1-49
Anyway, as far as I can see from your example, you don't need to create the JSONModel like you did in point 4. Manifest handle the creation for you. So in your controller you already have a JSONModel created and you can access it via
Nice blog ..well explained for new person in this area like me..The only point which Michael pointed out ....i also tried and it only worked when we gave the URL to json file....why?
Thanks
Dheer
Hi Dheerendra, here you have a full working example that uses JSONModel from manifest.json: https://github.com/StErMi/openui5-swissknife/tree/master/test/demo-1-49
Can you provide me an example code? Maybe I can give an hint to it.
Thank you very much Ricci.
Thanks Emanuele Ric, 🙂
Hi Ricci,
Really very one of the nice blog. Thanks for sharing with us. I have used in my one of the requirement. It's working but if I want to do multiple time then there is failure.
Do you have any insight how to achieve this? Sorry to asking question here as could not find any help document any where.
I have to show same kind of information on click of 3 separate Generic tiles in sap ui5. On click of first time need to show title, image and description similarly for the other tiles as well same field but data would be different. It is JSON model and I have prepared json file in default model same json file path has been defined. I can access data in case of first tile click but in other cases getting below error. I have used manifest.json configuration no controller code here. Error : "Assertion failed: list bindings support only a single template object" manifest.json code : "dataSources": { "init_data": { "uri": "model/data.json", "type": "JSON" } } "": { "type": "sap.ui.model.json.JSONModel", "dataSource": "init_data" } Json file structure : { "hrAppCollection": [{ "Heading": "TimeSheet Entry app", "AppPicUrl": "./image/timesheet.jpg", "PlaceHolderText": "Approval of Firefighter Access Request submitted for Production system instances." }, { "Heading": "Approve Firefighter Request", "AppPicUrl": "./image/timesheet.jpg", "PlaceHolderText": "Approval of Firefighter Access Request submitted for Production system instances." }] } I have tried using named model concept and did some json file data manipulation but I am not able to figure out how to achieve this. Let me know if you need any further information on the same.
BR,
RK