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.
Related
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
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"/>
When I bind I normally just enter the name of the property which exists in the DataContext
EG
Text = {Binding MyProp}"
When I use relative source, I have to use DataContext
Text = "{Binding RelativeSource={RelativeSource AncestorLevel=1, AncestorType={x:Type UserControl}, Mode=FindAncestor}, Path=DataContext.MyProp }" />
I must be missing some basic understanding as I don't see why I need to include the word DataContext in the path: Path=DataContext.MyProp, I had assumed it has implicit. If I remove DataContext from the string, then it won't bind.
RelativeSource will change the target to, in this instance, UserControl. This way you can bind to elements on the UserControl, such as its Width/Height/etc. In these cases having an implicit DataContext would be counter-productive.
I am new to rails and haven't really done to much with data outside of the model.
I have a form that references a table controller for files. I want to add an dropdown that will display a list of projects from a project table for the user to assign a the file to a project if they want too. Assigning a project is not a requirement. The file can be unassigned to a project. I do have a project_id column in the file table for those projects assigned but it is allowed to be null and I did not build a relationship because I need to have cases where there are none.
Can someone please tell me how to do this?
When they evaluate the file, the screen posts back with a save or update button depending if it has already been saved in the database.
At the same time as the save and update pop up on the right I want to display a list box of the projects with an assign project button. If new just a list, if update either just a list because not assigned or display the selected value in the list if already assigned, while allowing them to change it from the list if desired.
In the file controller method that posts back to the UI I have this code:
#file_alias_filedata = FileAliasFiledata.all
#projects = Project.all
for update
#projects = Project.find(params[:id])
In the form I have this code:
<p> <label> Select Project to Assign:</label> <br />
<%= select_tag 'projects', (#projects.present? ? options_for_select(#projects, #selected_project) : []) %> </p>
The form runs but I get this in the dropdown box:
#<Project:0x))7ff531ab4518>
Can someone please help me figure out how to accomplish my task and why I see the strange box value?
What am I doing wrong?
Thank you for your help!
Assigning a project is not a requirement. The file can be unassigned
to a project. I do have a project_id column in the file table for
those projects assigned but it is allowed to be null
From the docs:
belongs_to(name, scope = nil, options = {}) public
Specifies a
one-to-one association with another class. This method should only be
used if this class contains the foreign key. If the other class
contains the foreign key, then you should use has_one instead. See
also ActiveRecord::Associations::ClassMethods’s overview on when to
use has_one and when to use belongs_to.
Methods will be added for retrieval and query for a single associated
object, for which this object holds an id:
association(force_reload = false)
Returns the associated object. nil is returned if none is found.
Likewise,
has_many(name, scope = nil, options = {}, &extension) public
Specifies
a one-to-many association. The following methods for retrieval and
query of collections of associated objects will be added:
collection(force_reload = false) Returns an array of all the
associated objects. An empty array is returned if none are found.
But belongs_to() and has_many() are supposed to make things more convenient for you. You certainly do not have to use them.
Next,
and why I see the strange box value? What am I doing wrong?
You see the strange value for the same reason the following two loops display different things:
class Dog
attr_reader :name
def initialize(name)
#name = name
end
end
#dogs = [
Dog.new("Sam"),
Dog.new("Betty"),
Dog.new("Pete"),
]
#dogs.each {|dog| puts dog}
#dog_names = #dogs.map {|dog| dog.name }
#dog_names.each {|dog_name| puts dog_name}
--output:--
#<Dog:0x0000010099a308>
#<Dog:0x0000010099a2b8>
#<Dog:0x0000010099a268>
Sam
Betty
Pete
You will see the same result if you do something like the following in a view:
<div>
<%= select_tag "dog", options_for_select(#dogs) %>
</div>
<div>
<%= select_tag "dog_name", options_for_select(#dog_names) %>
</div>
If you read the docs here:
http://apidock.com/rails/ActionView/Helpers/FormOptionsHelper/options_for_select
...you will see several examples, which should make it clear that options_for_select() takes an argument that is:
An array of Strings.
A Hash where both the keys and values are Strings.
An enumerable that iterates over some Strings.
etc.
Do you see a pattern? It's Strings! options_for_select() needs an argument that consists of Strings. If the argument is not a collection of Strings, e.g. an array of project objects, then options_for_select() tries to convert the objects to strings by calling to_s() on the objects. And the default to_s() method is Object#to_s() which is inherited by all objects and produces a string containing the class name and the object_id.
I am also new to rails, but I think you can try using the options_from_collection_for_select method.
<%= select_tag :search_state, options_from_collection_for_select(State.find(:all, :select => :name), :name, :name) %>
Hope this help. Cause it certainly helped me.
I am trying to inherit the "contactInfo" item and create a new item descriptor.. Something like this as given below..
<item-descriptor name="testContactInfo" super-type="contactInfo">
<table name="test_contact_info" type="auxiliary" id-column-name="contact_id" shared-table-sequence="1">
<property name="fixedlinenumber" column-name="fixed_line_num" data-type="string"/>
</table>
</item-descriptor>
I get the following error when i start the server.
14:19:52,856 ERROR [ProfileAdapterRepository] Error parsing template: atg.repository.RepositoryException: Your item-descriptor definition for testContactInfo has super-type contactInfo but no sub-type attribute.
what am i doing wrong here? I have kept the definition in userProfile.xml
First question: are you actually looking to create a subtype of the contactInfo item descriptor - that is to say, are you expecting there to be some items in your system of type contactInfo and some items of type testContactInfo - or are you just looking to add a custom property to the existing contactInfo item descriptor?
If you are actually trying to create a subtype of contactInfo, then you need to modify the descriptor of contactInfo to tell it how to differentiate between items of type contactInfo and items of type testContactInfo. You will need to add a property, say contactType, to contactInfo and set the sub-type-property attribute
<item-descriptor name="contactInfo" sub-type-property="contactType" ...>
...
<property name="contactType" data-type="enumerated">
<option value="standard"/>
<option value="test"/>
</property>
...
</item-descriptor>
and then you can subtype it
<item-descriptor name="testContactInfo" super-type="contactInfo" sub-type-value="test">
...
</item-descriptor>
If, however, you are just looking to add a custom property to it, you can very well add to the existing definition. You do not need to subtype to extend an out-of-the-box item. For example
<item-descriptor name="contactInfo">
<table name="test_contact_info" type="auxiliary" id-column-name="contact_id" shared-table-sequence="1">
<property name="fixedlinenumber" column-name="fixed_line_num" data-type="string"/>
</table>
</item-descriptor>
will result in a new property called fixedlinenumber added to the standard contactInfo item.
Item-descriptor inheritance can be done in two ways. You can:-
Add new properties for existing item-descriptor.
Here you can add many properties to an existing item-descriptor. This can be out of the box, or your custom repository.
For example, you can have a employeeId property to contactInfo item-descriptor, which would be available for all contactInfo items.
Create a sub-type of an item-descriptor.
This is generally used to have distinctive properties for a particular item-descriptor.
For example, in your contactInfo type, you can have a "employeeContactInfo" wherein you want to store an extra employee id, and you can have a "employeeId" only for this type.
So, it basically depends on your requirements. You can see some details on this website.. nice tutorials:-
http://learnoracleatg.blogspot.in/2014/11/art203-how-to-extend-out-of-box-non.html
and
http://learnoracleatg.blogspot.in/2014/12/art204-how-to-add-new-item-descriptor.html