Closed tstorch closed 8 years ago
If I understood you would like to use static strings in the data binding syntax. This is currently a well-known limitation in SAPUI5, all parts of the data binding syntax have to be loaded from a model. We have internally discussed it already and we think that the separation between UI is more clear if no data is defined on the view directly so we encourage you to define the data in the controller.
But nstead of your workaround there is a lot easier solution to this, you can simply define a view model in the controller as a JSONModel and load the properties from there. You can see this in action for example in the worklist tempalte or the corresponding tutorial: https://sapui5.hana.ondemand.com/explored.html#/sample/sap.m.tutorial.worklist.03/code/webapp%252Fcontroller%252FWorklist.controller.js
Check the onInit method, there the view model is set up, also as in your use case with i18n model and used in the Worklist.view.xml file.
Also, in your case, you can use an i18n text with a placeholder and use the "jQuery.sap.formatMessage" formatter with no controller code at all. Check the worklist tutorial, it is all in the code of that one.
Hope that solves your issue.
Michael
Sorry for being imprecise. This was not my problem. What wanted to do is something like this only with i18n
<!-- view -->
<!-- ... -->
<Text text="Some text with {viewModel>specificData}"/>
<Text text="Some other text with {viewModel>specificData}"/>
<!-- ... -->
As you see in my example I already use a view model in the view, which is here called masterView
. In it I store some data (above /itemCount
). Now I would like to use /itemCount
in two places of an xml view as part of a binding. This bindings should load each a different i18n string an stick the same model data (/itemCount
) in it (like with getText
combined with getProperty
). To illustrate it here an example of how it would be solved currently:
Warning: Code only for demo purposes and _not_ tested
// controller
// ...
onInit: function() {
var oBundle = this.getResourceBundle(),
specificData = getCurrentSpecificData(),
viewModel = new JSONModel({
textA: oBundle.getText("MessageA", specificData),
textB: oBundle.getText("MessageB", specificData) // same data as in textA
});
this.setModel(viewModel, "viewModel");
}
// ...
updateText: function() {
var oViewModel = this.getModel("viewModel"),
oBundle = this.getResourceBundle(),
specificData = getCurrentSpecificData();
oViewModel.setProperty("textA", oBundle.getText("MessageA", specificData));
oViewModel.setProperty("textB", oBundle.getText("MessageB", specificData));
}
// ...
<!-- view -->
<!-- ... -->
<Text text="{viewModel>/textA}"/>
<Text text="{viewModel>/textB}"/>
<!-- ... -->
As you see, if specificData
changes, I alwaya have to update two properties.
This seems very unnatural and tedious. I figured something like this would be more fitting:
// controller
// ...
onInit: function() {
var specificData = getCurrentSpecificData(),
viewModel = new JSONModel({
specificData: specificData
});
this.setModel("viewModel");
}
// ...
updateText: function() {
var oViewModel = this.getModel("viewModel"),
specificData = getCurrentSpecificData();
oViewModel.setProperty("specificData", specificData);
}
// ...
<!-- view -->
<!-- ... -->
<!-- this is one possibility of syntax and arguably not the best/most intuitive -->
<Text text="{ parts: [ 'textA', 'viewModel>specificData' ], formatter: '.formatter.i18n' }"/>
<Text text="{ parts: [ 'textB', 'viewModel>specificData' ], formatter: '.formatter.i18n' }"/>
<!-- ... -->
I think, @Michadelic mentioned a solution for your problem already:
Also, in your case, you can use an i18n text with a placeholder and use the "jQuery.sap.formatMessage" formatter with no controller code at all. Check the worklist tutorial, it is all in the code of that one.
The trick is to use a ResourceModel (a wrapper around ResourceBundles that makes i18n texts available in data binding). Essentially, it used a given binding path as key into the resource bundle and returns the associated text (in the current session locale).
To get the formatting capabilities of getText
you can use jQuery.sap.formatMessage
as a formatter. getText
internally uses the same method.
Combining all this leads to the following declarative binding:
<mvc:View
resourceBundleName="sap.ui.core.messagebundle"
resourceBundleAlias="i18n"
xmlns:mvc="sap.ui.core.mvc"
xmlns:l="sap.ui.layout"
xmlns="sap.m">
<l:VerticalLayout>
<Text text="raw: '{/fileSize}'" />
<Text text="{parts:['i18n>FileSize.Kilobyte', '/fileSize'],
formatter: 'jQuery.sap.formatMessage'}" />
<Text text="{parts:['i18n>FileSize.Byte', '/fileSize'],
formatter: 'jQuery.sap.formatMessage'}" />
</l:VerticalLayout>
</mvc:View>
For illustration purposes, I've used a resource bundle from UI5 and text keys from that bundle for which the texts contain placeholders.
A working example can be found here: http://jsbin.com/xamicofogi/edit?html,output
One pitfall I should mention: in contrast to all other models, a binding path for a ResourceModel must not start with a slash.
OK. Now I got it. Sorry for my confusion! I did not find the formatter: 'jQuery.sap.formatMessage'}"
part in the tutorial.
Thanks a lot, @Michadelic @codeworrior !
OpenUI5 version: all
Browser/version (+device/version): all
I wanted to reproduce the
getText
method of bundels in xml. The following code is taken from here and works quiet well, but I'm very unhappy about the JSONModel bending. In short: An model is introduced which returns ongetProperty(someText)
justsomeText
without any evaluation.This code (currently) seems to must be that complicated (read: it's a hack) because there is no way to prevent model path evaluation (
getProperty
) in theparts
part of the xml binding.What could be done? There are two feasable options I see:
getProperty
, i.e. no more JSONModel bendingparts
in xml bindings.I personally would prefer 2. This would also allow for more general use cases of formatters. My assumption though is, that this would me more complex to implement than option 1.