What's the usage of setBindingContext() and the difference from element binding? - sapui5

In the 1.5.2.3 Defining a Binding Path section of OpenUI5 demokit:
A context exists either for each entry of the aggregation in case of aggregation binding or can be set explicitly for a control by using the setBindingContext method.
In the 1.5.3.3 Element Binding section of OpenUI5 demokit:
Element binding allows to bind elements to a specific object in the model data, which will create a binding context and allow relative binding within the control and all of its children.
It seems to me that the two techniques actually do the same thing. They both create a binding context for a control so that bindings of the containing controls will resolve relatively to it. But what's the difference between them? In what scenario will either of them come into play?
The setBindingContext doesn't work in the following code:https://jsbin.com/bigope/edit?html,output
However, if I change oPanel.setBindingContext("/nameinfo"); to oPanel.bindElement("/nameinfo");, it works, why?

setBindingContext requires you to pass a Context like this:
oPanel.setBindingContext(new sap.ui.model.Context(oModel, "/nameinfo"));
The difference between those two is conceptual.
The Binding Context is used as a parent context for all bindings (for that model) in that Control or its children. It only holds a reference to the used model, (a part of) the path and optional another parent context. It is used when creating relative bindings.
The bindElement method on the other hand behaves like every other bind* method.
It creates a binding (in this case, a ContextBinding) which allows change events, data binding, etc.
Additionally the created ContextBinding also serves as a BindingContext for other bindings, just like a Context added with setBindingContext would do.
Not confusing at all, right ;)?
Reading the code for ManagedObject might help you to understand the internals better. (bindObject = bindElement)

Related

Anylogic: Declare parameter of type ArrayList

I'm building a class (sorry - Agent) that will work with a set of Tank objects (Fluid Library) - doing things like monitoring individual levels or total level of all tanks, reporting on levels and initiating actions based on levels - things of that nature. For argument's sake let's call it a "TankMonitor" agent.
Ideally I'd like to be able to define a Parameter in my "TankMonitor" agent that allows me to define the tanks of interest when I place a TankMonitor in main. I have tried to define the type of the parameter as Other - ArrayList<Tank> however I don't know how to set up the next step to allow me to populate the ArrayList of Tanks when I put an instance of this agent in main. My preference would be to have a list type control to populate the ArrayList - much like the way the AnyLogic Seize block allows you to specify multiple resource pools to choose from.
Has anyone attempted this before and been successful?
This is possible as follows:
Change the type to "Other" and then 'Tank[]' , i.e. an Array of Tanks
Change the control type to "one-dimensional array"
Example below. Now you have the same UI to pre-define tanks at design time for your agent instance.
In addition to Benjamin's perfect answer, I'd just add the manual workaround, which is not needed here but can be useful when the parameter in question has a more complicated structure than covered by the pre-made controls, say a list of lists, a map, or similar.
In such a case, the Control Type is still Text, and populating it in an instance happens by pointing it to a new object of the parameter's type. E.g. for an ArrayList<Tank> parameter, you might instantiate a new ArrayList object, which you fill with a list of objects like so:
new ArrayList<Tank>(Arrays.asList(tankA, tankB))
In the Java code, whatever is written into that text box will end up on the right side of a parameter assignment statement in the embedded Agent instance's auto-generated parameter setup function. Therefore, multi-statement code won't work in this spot. Instead, if the process of building the parameter value doesn't fit neatly into a single expression, you can hide the code in a function which returns the desired object, and call that from the parameter's text box.

Does UI5 Remember's previous entity

I am building simple crud for an entity. Initial state is read on particular entity(key) using view>form.bindElement('/entity(key)').
when I click on new button I clear the form and when the cancel button is clicked during the new/create process(without performing the save), how to go back to the previous entity. Is there some place ui5 stores, the previous entity or should I have some variable and assign it to the controller.previousEntity = oldsPath?
what are the different members in the oModel,it start with
a(aBindings)
b(bUseBatch)
m(mContexts)
o(oHeaders)
p(pCallAsync)
s(sPathUrl).
Is there a naming convention in these?
From what I can see, there are following things you need to notice and work upon.
Its generally not a good idea if you use the same form to display and to create/update also. A simpler approach would be to
use a new popover to show the form for create and in that case, the view binding would not be changed when you cancel the operation.
However, if you still want to use the same form, yes you would have to bind the view/form again on cancel operation. You can have a variable declared in the Component.js to store the path for you. In UI5, the model captures the current state to ensure the back the binding concept by default.
You can check all properties and their definitions here: oData Model
Yes, there is a naming convention followed here.
a - Array, s-String, b- Boolean etc.
Read more about Hungarian notations for naming conventions
The previous entity is still there in the cache (ODataModel.oData), but you'll need to re-bind it. For that purpose, as you have written, you'll need to store the path to the entity yourself. Once you bind the control, I don't think the previous binding context is stored somewhere (why should it).

Is there a Binding.scala way to append dom elements?

I would like to append a Binding node to another Binding node without re-rendering the parent node.
Is there a specific way how Binding.scala would handle this?
Bindings can be nested and composed, so in general it's not something you need to think about. A Binding[T] represents an object that is dynamically bound and will be recomputed when any upstream Binding's value changes.
Your question is a bit ambiguous so you may want to clarify or add a code example, but there is nothing extra you need to do to accomplish your goal. Look at the examples and also this section of the README:
https://github.com/ThoughtWorksInc/Binding.scala/blob/11.0.x/README.md#precise-data-binding
Also, I made a quick example of what I'm talking about here:
https://scalafiddle.io/sf/XZgtwHM/1
If you open up your browser console, you'll see that the method that renders out the parent node is only called the first time, but if you click the button more child elements will be appended without the parent node being affected. Inspect the HTML and pay attention to the id of the parent div, it is set up to increment the ID each time it gets rendered, and the id remains as "parent_1" the whole time.

Accessing om.next sub-component state

I'm just picking up om.next and have run into a situation where I've got some form inputs realized as components which hold on to local state, e.g. validation state, actual input value, etc--this state is updated and accessed via om.next/update-state! and om.next/get-state. The trouble with this seems to be when I wrap the inputs in a form in a parent component I'm unsure how to get the state held by the input components. Is it better to pass along the parent component as a property of the input component? What about situations where there is no parent component?
It seems to me that there are 2 options for the use case you want to achieve:
pass the parent component as an argument as you said
have an entry in the global app-state that represents the current form being edited, which you can update via transact! irregardless of the component corresponding to the input. This way every component that represents an input knows where in the app-state to update itself (which key in the current form) — probably captured succintly in one mutation function.
1) is probably the easiest to implement given the code you have currently, but I always like to go for 2) because it doesn't deviate from the "single source of truth" opinion that Om Next recommends (and tries to enforce). Form data is in fact business data, which might not be desirable to have scattered in components. Testability is just one advantage that I immediately see from such approach.

Using i18n .properties-defined maps in a UiBinder template

Suppose I have a <String,String> map defined in my i18n .properties files, e.g.:
userGroupMap = 0, 1, 2, 3
0=Factory
1=Administrators
2=Superusers
3=Operators
The dev guide explains that introducing a corresponding Map<String,String> userGroupMap() method in MyConstants implements Constants interface will result in calls such as MyConstants.userGroupMap().get("1") returning the localized "Administrators". So far so good.
What about UiBinder? How do I use one of the mapped values in a UiBinder template? Is there a syntax I'm missing, e.g. <ui:msg key="userGroupMap:1">Administrators</ui:msg> (doesn't actually work)?
One way you could do this would be a non-xml solution, but you could use a #UiFactory to help with the creation of the specific fields or labels that you need I18N'd. But to me, this particular problems seems like it begs the solution below, since you seem to be looking to decouple your widgets from your screen or panel layouts.
I struggled with this, and for my implementation, I ended up making core widgets with UiBinder backing for their internals(for instance a label and a text field with a help button), and then passing in a 'fieldKey' that was used as a prepender for all the I18N keys in the various maps.
For instance, for the PartNumber field, I had a key in the following maps: labelTexts(), helpTexts(), tooltipTexts(), defaultFieldValues(). Then in the constructor for that widget, I would pass in the string key 'partNumber', and that would be used to build up all the keys needed, so I would call labelTexts().get('partNumberLabelText'), helpTexts().get('partNumberHelpText'), etc.
I didn't want to do this directly in UiBinder, since I wanted the widget key to map back to it's display information, so I could create a widget with as little input information as possible, in many cases just the key and then the widget (provided it was configured in the I18N setup correctly) would just populate everything from the maps based on that.
From a design standpoint, for me it didn't make sense to have separate UiBinders for the screen sets, they were composited from objects that defined the screen layout and relation of all the widgets (meaning that you could define screen content at runtime).