what are parts: and path: in sapui5 and why are they used? - sapui5

What is the use of parts and path in SAPUI5 while dealing with models?
Can someone explain me with respect to the following code (where invoice is a JSONModel)?
<mvc:View
controllerName="sap.ui.demo.walkthrough.controller.InvoiceList"
xmlns="sap.m"
xmlns:mvc="sap.ui.core.mvc">
<List
headerText="{i18n>invoiceListTitle}"
class="sapUiResponsiveMargin"
width="auto"
items="{invoice>/Invoices}">
<items>
<ObjectListItem
title="{invoice>Quantity} x {invoice>ProductName}"
number="{
parts: [{path: 'invoice>ExtendedPrice'}, {path: 'view>/currency'}],
type: 'sap.ui.model.type.Currency',
formatOptions: {
showMeasure: false
}
}"
numberUnit="{view>/currency}"
numberState="{= ${invoice>ExtendedPrice} > 50 ? 'Error' : 'Success' }">
<firstStatus>
<ObjectStatus text="{
path: 'invoice>Status',
formatter: '.formatter.statusText'
}"/>
</firstStatus>
</ObjectListItem>
</items>
</List>
</mvc:View>

Welcome to StackOverflow!
What you are referencing is called binding. In your example, you have:
List binding: items="{invoice>/Invoices}".
Simple property binding: numberUnit="{view>/currency}".
Composite property binding: number="{parts: [...]} (with explicit syntax) and title="{invoice>Quantity} x {invoice>ProductName}" (with complex syntax).
Expression binding: numberState="{= ${invoice>ExtendedPrice} > 50 ? 'Error' : 'Success' }"
The SDK has a few extensive documentation pages about these topics, under the chapter Data binding.
List binding is used to create a collection of controls, based on the data inside the model (either based on a list or a map of objects). Conceptually, you can imagine that UI5 loops through your values and instantiates the corresponding control using a template or a factory function. The path in this case is the (relative or absolute) path towards the collection.
Simple property binding is used just to fill in a property of a control from your model based on a single scalar field in the model. The path here is the (relative or absolute) path towards the property.
Composite property binding can be used to fill a property of a control based on multiple fields, which are combined through either a formatter function or a type (like the currency in your example). For example, when using a formatter, each part will be passed as a parameter to your function (e.g. if you have 2 parts, your formatter should expect 2 parameters). The parts here are used to define each individual field that you want to use when computing the property value.
Expression binding or the complex syntax is simply a form of syntactic sugar to allow you to define a formatter inline without having to write a dedicate JS function.
You always can use the simplified syntax property="{/path}" or the extended syntax property="{path: '/path'}", which are equivalent (but you are forced to use the extended syntax once you want to specify more binding parameters).

Simply speaking, within path you can only bind with exactly one property or value, and parts can let you bind multiple properties or values which sometimes is very useful.
In you example, the Currency formatting requires two parameters, one is amount, the other is currency, you have to use parts to parse two parameters.
Also when you write your own formatter function, if you would like more parameters, you can also use parts to receive these parameters.
This is called Composite Binding.
Regards,
Marvin

Related

Correct Syntax of Element binding in XML view with JSON model

Trying to get right syntax for context binding in XML view. I have a JSON model and set the model to view with name "company" inside controller. When I use absolute path, it works but when I use relative path, it doesn't. It seems, view is unable to access the model in second case.
My Code
<Text text ="{company>/data/name}" width="200px"/>
<Input binding="{company>/data}" value ="{name}" width="200px"/>
When binding a property, you also have to provide the name of the model. Otherwise the "nameless" default model is assumed. But since all your data is in the company model you have to explicitly state that name for your value.
<Input binding="{company>/data}" value="{company>name}" width="200px"/>

Aggregation Binding to Child Collection

In an XML view I have a JSON model bound to the page with the name 'foo'. The model's object has a 'name' field and child collection 'bar' (that has a 'code' field) that I want to show in a list. This is modeled as such:
JS Code
var foo = { name:'My Name', bar:[{ code:'Code 1' }, { code:'Code 2' }] }
var fooModel = new sap.ui.model.JSONModel(foo);
page.setModel(fooModel, 'foo');
page.bindElement('foo>/');
XML Markup
<Label text='{foo>name}'/>
<List items='{foo>bar}'>
<StandardListItem title='{foo>code}'/>
</List>
Notice that the list item's values for the child 'bar' array are resolved via the name 'foo'. At least this works for me and I have found no other way to reference them in the list.
But the problem is how do I get the top-level 'foo' object data in my list-item also? Say I wanted to show the 'name' field also in the list items?
In other words, is there a way to do the equivalent of the following, where I can reference the child collection by a different name? Is there some way to achieve this?
<List items="{ path:'foo>bar', name='bar' }">
<StandardListItem title='{bar>code}' info='{foo>name}' />
</List>
You need to use an absolute path to bind the name property. Absolute means the complete path to the property within your model. The opposite is a relative binding path. Here you just use a property somewhere within your model and set a binding context to tell the runtime where your property is located within the model. You do this by using:
page.bindElement("foo>/");
Now the runtime will apply this information to all relative bindings against the model foo within this page. Therefore you can write foo>bar and the runtime automatically look up foo>/bar. However within the item aggregation this does not work, because the bar object does not have a property name. Therefore you need to use a absolute binding path to bind the property.
<List items="{foo>bar}">
<StandardListItem title='{foo>code}' info='{foo>/name}' />
</List>
You find an explanation of the binding syntax for JSONModel in the documenation.

Complex Binding in SAPUI5 XML View

I am trying to convert a string value to Boolean while binding it from a JSONModel. Ideally the value in my model is "true"/"false" and I want to bind it to the visible property of an item. The model is defined to be TwoWay binding but I guess that does not matter in this case
I have declared "complex binding" in the index.html.
data-sap-ui-xx-bindingSyntax="complex"
Then I create my XML view and bind the property from the model as below:
<P13nColumnsItem>
columnKey="{tableVariantAFModel>Fieldname}"
visible="{path:'tableVariantAFModel>Visible', type: 'sap.ui.model.type.Boolean', mode: 'sap.ui.model.BindingMode.TwoWay'}"
index="{tableVariantAFModel>DisplayOrder}">
<P13nColumnsItem>
When I run my app,it throws the below error:
Is there any step I am missing?
Also, I need to add this app to the Fiori Launchpad, so I need to define the complex binding in manifest.json file rather than in index.html . Where can I define it in the manifest file.
For simple use cases like this you can use an expression binding instead of implementing additional logic somewhere.
<P13nColumnsItem>
columnKey="{tableVariantAFModel>Fieldname}"
visible="{= ${tableVariantAFModel>Visible} === 'true'}"
index="{tableVariantAFModel>DisplayOrder}">
<P13nColumnsItem>
i would advise to use a formatter. See here. In the formatter you could write:
visible="{path:'tableVariantAFModel>Visible', formatter: '.formatter.stringToBoolean'}"
in the formatter you could create the function like:
stringToBoolean: function(_stringBoolean){
(_stringBoolean === "true") ? return true : return false;
}
You have to make sure that you instantiate the formatter in your controller, or optionally you could choose a function in your controller itself.

Why after set formatter of a property binding of TextField, the json model binding becomes "oneway"?

I'm writing an application using XML view. There is a JSON Model 'data' set on the view, when I put a text field like below, I can get the updated value from user input.
<TextField value="{path: 'data>/xxx'}" />
But if I put a formatter in the binding like below, then it's impossible to get the updated value back.
<TextField value="{path: 'data>/xxx',
formatter: 'abc.util.formatter.yyy'}" />
Why is that? How to use JSONModel TwoWay binding and formatter at the same time???
The binding mode switches to OneWay as formatters do not support bi-directional data flow, as they are used for formatting property values for the output. A TwoWay binding includes also parsing and validating input before it is written to the model. If you need this, you should use a type instead. This is the same for all model type, not only the JSONModel.
Maybe your binding sytle is problem.
Can you try this in your index.
data-sap-ui-xx-bindingSyntax="complex"

What are some handy tricks for submitting Grails forms?

Everybody's aware of passing parameters to a controller via a html form:
<g:form action="save">
<g:textField name="text1" />
</g:form>
And I'm vaguely aware of being able to structure these parameters into some sort of object notation in Grails:
<g:form action="save">
<g:textField name="text.a" />
<g:textField name="text.b" />
</g:form>
With very little idea how they are structured in the controller (objects? hashmaps? I recall having to use .value at some point using the latter example).
So I guess this question is really two questions:
How does Grails handle parameters in object notation like the second example? Can you stick them into arrays too?
What are some other tricks regarding form submission and its parameters that can make forms with very complex and iterative data trivial to handle in the controller? For instance, ATG allows you to bind form fields to beans and walk its entire property graph to find the property you need to set.
The second notation "text.a" is used to disambiguate data conversion from properties to domain objects. For example, if you have 2 domain objects each with a property "a", if you do domObj1.properties = params and domObj2.properties = params the value will go to both domain objects which may not be what you want. So in your view you should have variables domObj1.a and domObj2.a and in your grails controller you can instantiate using def domObj1 = new DomObj1(params["domObj1"])
By your second question if you mean whether you can iterate over objects, you very well can, using GPath syntax in a ${} wrapper, for e.g check out the code in the id property below.
<td><g:remoteLink controller="device" action="getDevice" id="${objInstance.prop1.prop2.id}" update="propDetail">${fieldValue(bean: objInstance.prop1, field: "prop1")}</g:remoteLink></td>
The example above also shows an ajax way of form submission from grails gsp.