Binding blocks of a Section to another Section - binding

I have a FlowDocument with several Paragraps and Tables, this FlowDocument should repeat itself presenting the exact copy after the middle of the page. I'm using 2 Sections to achieve that.
To make thing easy, I'm trying to bind a section to another:
<Section x:Name="MainSection" Padding="10">
<!-- Lots of things -->
</Section>
<Section Padding="10" Blocks="{Binding ElementName=MainSection, Path=Blocks}"/>
But unfortunately, Blocks does not have an accessible setter. How could I replicate the contents without having to duplicate my XAML?
PS: I'm not using C# code to create the page visual, only to fill in the paragraphs and tables.

Create a custom control that inherits from Section and create a bindable property and instead of binding it to Blocks you bind it to the new property. Inside the custom control, handle the property changed for that new property and add the value to the actual Blocks property.

Related

UI5: Bind a simple property of a control to a property of an OData entity

I have an OData model which I successfully use to fill eg. a table in a SAPUI5 app:
<Table items="{globalSettings>/APP_GLOBAL_PREFERENCES/}">
etc.
The entity set APP_GLOBAL_PREFERENCES consists of entities each having a KEY and VALUE property, with KEY being the, well, key.
Now, I'm trying to bind the textproperty of a <Text>control to a property of a specfic instance of the entity:
<Text text="The base URL is '{globalSettings>/APP_GLOBAL_PREFERENCES('BASE_URL')/VALUE}'" />
In order for this to work, I have to create an element binding, as suggested here. In my case, I do it in the lifecycle method onBeforeRendering of the associated controller:
onBeforeRendering: function () {
this.getView().bindElement({
path: '/APP_GLOBAL_PREFERENCES',
model: 'globalSettings'
});
}
I don't understand why this step is necessary, and I would like to avoid it.
Can anyone explain why this step is required, or does anybody have a clue how to get by without it?
In UI5, there are 3 types of bindings:
Aggregation bindings can be used with aggregation (for example table or list items). This requires an array of objects from data point of view. In this case, you have to configure a so-called template, which will be repeated for every instance of the aggregation. Here, you need to use relative binding, so you don't have include the array reference itself in the binding path.
Element bindings are used to bind objects from the model to a control (views are also controls!). If the control has any child elements, these child elements can be bound to any property of this object using relative binding.**
Property bindings are the elementary parts of a binding procedure; each control has more or less properties, and you can assign model values to these properties using property binding.
** This means, that in your Text control you have to use a relative binding, so just use {VALUE}. However, make sure that if APP_GLOBAL_PREFERENCES in your model points to an array, you have to select a specific item in your bindElement (for example:
this.getView().bindElement({
path: '/APP_GLOBAL_PREFERENCES('BASE_URL')',
model: 'globalSettings'
});).
Edit:
Ok, now I see your problem! Answering your question: it's not necessary.
If you use the this.getView().bindElement(..) property, you can use relative path in your text control (assuming that you include the selection of the proper item in this segment). My examples are based on JSONModel:
this.getView().bindElement({
path: '/APP_GLOBAL_PREFERENCES/0',
model: 'globalSettings'
});
Then you can do this in your view:
<Text text="{globalSettings>text}" />
If you skip the bindElement (but you've assigned the model to the view), you need to use the following path:
<Text text="{globalSettings>/APP_GLOBAL_PREFERENCES/0/text}" />
If you are implementing a detail view, which gets the ID of the selected item as an URL parameter, it's recommended to use the bindElement with the selection to the given parameter; then in your XML view, you can use relative binding and you don't have to care about the ID of the item.

Can Orbeon controls have multiple values?

I think the answer is no, but the question has been put to me so I'd like to confirm. My understanding is that any custom XBL control that I create for use in Form Builder can have one and only one value. Is this correct?
I have always assumed this because the control name is then used in the data instance as the name of the node which contains the the value.
This question comes from the desire to have reusable components with multiple values, for example, an Address control so that addresses can be recorded consistently and the same set of fields does not need to be added many times. Orbeon does have some support for this in the form of Section Templates but because the control names stay the same in each instance of a Section Template this does not work well with our design.
The best idea I've had is that a custom control which records multiple values could encode all the values into a single text string for example in JSON. Of course, this is not ideal.
Are there any other options?
It is possible for controls to have multiple values. When that happens the values are typically stored in nested elements. I.e. a control could bound to an element <address>, and could create nested elements <street>, <city>,<country>, etc to store the different parts of the address.
In practice, you can look at how this is done in the Image Annotation annotation control (see wpaint.xbl), which creates nested elements <image> and <annotation>, leveraging the xxbl:mirror="true" functionality.

OmniFaces o:validateAllOrNone in ui:repeat or h:dataTable

Is it possible to use OmniFaces <o:validateAllOrNone> (which is pretty cool ;)) within an <ui:repeat> or <h:dataTable>?
I need a table with each row having an input field column. You could either fill in none of these values or all of them.
If I put the <o:validateAllOrNone> within the <ui:repeat> or <h:dataTable> and use the id of the input field in components attribute, then the validator also gets triggered, if all fields are empty.
No, that's not possible. The components attribute must refer physically multiple components, not a single component which is rendered multiple times. It can however be used on physically multiple components which are rendered during same iteration round. The <o:validateXxx> multi field validator is not designed to reference a single component which is rendered multiple times. The only OmniFaces validator which does that is <o:validateUniqueColumn>.
If you want to use the <o:validateXxx> multi field validator on dynamic inputs based on a collection, then your best bet is to use JSTL <c:forEach>. It will build physically multiple components.
E.g.
<c:forEach items="#{bean.items}" var="item" varStatus="loop">
<h:inputText id="input_#{loop.index}" value="#{item.value}" />
</c:forEach>
Assuming that there are 3 items, this will dynamically create JSF components with IDs of input_0, input_1 and input_2. Then you can just use <o:validateXxx> as follows (put it outside the loop!)
<o:validateAllOrNone components="input_0 input_1 input_2" />
You can replace the hardcoded string in the above example by an EL expression which returns the desired space separated string of component IDs from a backing bean.
<o:validateAllOrNone components="#{bean.inputIds}" />
An alternative would be to create a <x:validateAllOrNoneColumn> yourself or to post an enhancement request at OmniFaces issue tracker. It would be not exactly trivial to alter the existing <o:validateAllOrNone> that a completely separate component is desired.

Why are the elements for a non-relevant section template missing?

I'm using a section template created by Orbeon Form Builder that I included in another form also created by Form Builder. When in this form we make the section template invisible, it disappears from the form instance.
Is it possible to make the section template invisible without loosing it in form instance?
For each section templates, Form Builder generates an XBL component which wraps the fields in that section. In the form that uses the XBL corresponding to the section template, in the XML for the instance, there is just one element for the whole section, and the XBL component is bound to that element. The XBL component "knows" what the XML for the fields in the section is, and at runtime, when it becomes relevant, it inserts them inside the element for the section. Hence, if the section never becomes relevant, those fields will be missing from the instance.
This behavior isn't consistent with what happens for regular sections, but it shouldn't cause any particular problem to Form Runner. Say, if you save the data without those fields, edit it later, and the section becomes relevant, the XBL component will then add the elements to the instance. For this reason, we created this issue.
I dont work on Form Builder, but you can make section/fields invisible using
<xforms:group> or
by using relevant condition in bind definition.
If you use <xforms:group> then the section/fields will not be removed from model instance.
If you use relevant condition, then the section will be removed from model instance when the relevant condition is false.

Binding to multple datasources in Silverlight with String.Format

I am trying to bind a label 2 (or more!) fields in a dataset in Silverlight 4. I get a localized string out of a resource file and do a String.Format on it like so:
<TextBlock Name="lblTotals" Text="{Binding TotalItems, StringFormat='You need \{0\} items and \{1\} products.'}" />
This works fine with 1 item but there's no way of doing multiple binds in SL4 it seems.
I found some blog posts on how to bind a single element to multiple fields but it does not seem to support the String.Format part which is critical.
The last caveat is that it is bound to an ObservableCollection, so when these fields change in the data the UI must update too.
Any suggestions? Thanks!
I found a solution here using a converter and binding to the whole object and passing in the string as a converter param.
Then the totals did not update when the grid values updated (despite being linked to OnPropertyChanged) - this was the solution hack here.

Resources