How to synchronize control values within different views - sapui5

I would like to know how to get the content of TextArea, assign the value to a variable, set it to a model, and then set the variable to another TextArea in another view. I have coded some examples and it works, but not on TextArea.
Here is the example code:
// In init of the Component.js
this.setModel(new JSONModel(), "TransportModel"); // JSONModel required from "sap/ui/model/json/JSONModel"
// In *.controller.js
this.getView().getModel("TransportModel").setProperty("/", {
"Serial": this.byId("mat_serial").getValue() // "mat_serial" == id of the Input box in XML view
});
In the last step, I set the Text from a different View (also XML and Input Box) with the Value of the Model Element.
<Text text="{TransportModel>/Serial}" />
That worked pretty well.
But how to do the same with the TextArea? How can I do it based on this model? The value that I want to use from the first TextArea should also be on a TextArea in another view.

UI5 supports two-way data binding. I.e. if the user changes something in the UI (e.g. user types something in the text area), that change will be reflected automatically in other bindings that listen to the change.
<!-- In view 1 -->
<TextArea value="{TransportModel>/Serial}" />
<!-- In view 2 -->
<Text text="{TransportModel>/Serial}" />
No need to get input values by hand. Simply let the framework synchronize the value.

How to use a local json model:
Create
initItemViewModel: function () {
return new JSONModel({
Serial: ""
});
}
this._oViewModel = this.initItemViewModel();
this.setModel(this._oViewModel, "TransportModel");
Using
this.getView().getModel("TransportModel").setProperty("/Serial", serial);
<Text text="{TransportModel>/Serial}" width="auto" maxLines="1"/>

Related

Event Handler for JSONModel Change?

Say, there's an sap.m.table whose items are bound to a JSON model - "/rows". Outside sap.m.table layout, there's a toolbar that contains "Add" button to add rows to the table. "Add" button adds rows to the table using model's setProperty method. Now, the requirement is to disable "Add" button when JSON model "/rows" length has reached 10. How do we create a handler to observe the changes of JSON model's "/rows" property? https://sapui5.netweaver.ondemand.com/1.52.22/#/api/sap.ui.model.Model/events/propertyChange states that
Currently the event is only fired with reason sap.ui.model.ChangeReason.Binding which is fired when two way changes occur to a value of a property binding.
This means that the eventHandler of propertyChange doesn't get triggered when JSONModel's setProperty() is called. Is there a way out where we can observe the changes of JSONModel's property changes - in this case, "/rows" property of the JSONModel?
Well I can think of several ways to achieve this
1. Standard view binding + formatter:
View
...
<Button text="Add" press="onPressAdd" enabled="{path: '/rows', formatter: '.isAddEnabled'}" />
...
Controller:
Controller.prototype.isAddEnabled = function(rows) {
return rows && rows.length < 10;
}
2. Expression binding (pure xml)
...
<Button text="Add" press="onPressAdd" enabled="{= ${/rows/length} < 10 }" />
...
3. JSONPropertyBinding (pure javascript)
You can call bindProperty on JSONModel to create a property binding that can be observed for changes:
https://sapui5.hana.ondemand.com/#/api/sap.ui.model.Model/methods/bindProperty
https://sapui5.hana.ondemand.com/#/api/sap.ui.model.json.JSONPropertyBinding
Controller.prototype.onInit = function() {
var model = this.getMyJsonModel();
var button = this.getView().byId("myButtonId");
model.bindProperty("/rows").attachChange(function(event) {
button.setEnabled(event.getSource().getValue().length < 10);
})
}

Setting multiple properties of a component with one function

I have a component in a list in a sapui5 XML view and I want to set multiple properties of that component with one function. E.g. I want to set text, status, tooltip and icon of an ObjectStatus together, because the values of those are all different facets of the same data. The issue is that i have to calculate the values to set to those properties from the model with the same relatively time-heavy function. If I write a separate formatter for each of those properties, it has to run the same function for each property. Instead of this I would like to write one function that runs this time-heavy function once and sets a value to all those properties at the same time.
To accomplish this, I have tried creating a sapui5 fragment that could be placed in the list and filled with different information by the createContent function for each instance of that fragment. However I cannot figure out how to do this.
In the view definitions I'm trying to instantiate the fragment like this:
<core:Fragment fragmentName="QuantificationParameter" type="JS" path="{project>}"/>
And then I'm trying to set different content to each instance of the fragment:
sap.ui.jsfragment("namespace.fragments.QuantificationParameter", {
createContent: function(oParentController) {
//Get the object bound to this list item
var derived; //Calculate some intermediate information from this object
return new sap.m.ObjectStatus({
icon: derived.icon,
text: derived.text,
state: derived.state,
tooltip: derived.tooltip
});
}
});
While debugging it seems that the createContent function of the fragment is run only once and I cannot figure out any way to access the data that I'm trying to bind to the fragment. Is there any way I can render different content to each instance of the fragment?
What you are searching for is called databinding.
But first of all: we do not use JS Fragments, due to the same reason we do not use JS views. Here s a little Blog written on that topic.
https://blogs.sap.com/2018/05/01/why-do-we-use-xml-views-rather-js-views-in-sapui5/
Now the databinding part:
I asume, that Fragment will have the same controlls for each instance and you just want the values to change. To do just that you need to create a JSONModel either in your BaseController or component.js. In this Model you store i.e. your Labels text.
Inside your Fragmet you bind that property to the label. Since JSONModels bindingmode is two way by default the Label will change dynamically if you update the model. You can update the model i.e. everytime the user clicks on one of your list items.
Framgmet example:
<core:FragmentDefinition
xmlns="sap.m"
xmlns:f="sap.ui.layout.form"
xmlns:core="sap.ui.core">
<f:SimpleForm
editable="true">
<f:content>
<Input
value="{baseModel>/inputA}"
type="Text"
placeholder="{i18n>placeHolder}"/>
<TextArea
value="{baseModel>/textA}"/>
<TextArea
editable="false"
value="{baseModel>/textB}"/>
</f:content>
</f:SimpleForm>
</core:FragmentDefinition>
creation of the model i.e in component.js:
var oBaseModel = new JSONModel({
inputA: "",
textA: "",
textB: ""
});
this.setModel(oBaseModel, "baseModel");
example for your press lit item funtion:
(should be in the controller of the view your list is located in)
onListPress: function (oEvent) {
var oLine = oEvent.getSource().getBindingContext("yourRemoteService").getObject();
this._oBaseModel.setProperty("/inputA", oLine.ListPropertyA);
this._oBaseModel.setProperty("/textA", oLine.ListPropertyb);
this._oBaseModel.setProperty("/textB", oLine.ListPropertyC);
}
You should really give that tutorial a go:
https://sapui5.hana.ondemand.com/#/topic/e5310932a71f42daa41f3a6143efca9c

How to show hide elements based on select inside a multifield in Touch UI AEM 6?

I have a dropdown that has two options "image" and "icon".
When the user selects "image" I want to show the pathbrowser and when he selects "icon" I will show a text field.
This is famous problem, now I want to do this when these above mentioned fields are inside a multifield in Touch UI.
So say I have two items under this multifield, when I select "image", in the select present in the first item(of the multfield) the OOTB showhide hides my "icon" textfield of the first and the second item entry in the multifield as well.
How do I resolve this ?
Long story short See Blog. I want to do this. Just that my fields are inside a multifield.
Note:
I was able to implement the Classic UI code using ExtJs field.nextSibling() so I don't affect the entries in the other multifield item entries.
Find the code below and for more details check this gitlink here
.content.xml
<enable
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/foundation/form/checkbox"
text="Enable"
id="enable"
value="true"
name="./enable"
class="cq-dialog-checkbox-showhide"
cq-dialog-checkbox-showhide-target=".button-option-enable-showhide-target"/>
<deleteEnable
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/foundation/form/hidden"
name="./enable#Delete"
value="true"/>
<showHideContainer
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/foundation/container"
class="hidden button-option-enable-showhide-target"
showhidetargetvalue="true">
<items jcr:primaryType="nt:unstructured">
<!-- some components to show/hide -->
</items>
</showHideContainer>
checkboxshowhide.js
(function(document, $) {
"use strict";
// when dialog gets injected
$(document).on("foundation-contentloaded", function(e) {
// if there is already an inital value make sure the according target element becomes visible
$(".cq-dialog-checkbox-showhide").each( function() {
showHide($(this));
});
});
$(document).on("change", ".cq-dialog-checkbox-showhide", function(e) {
showHide($(this));
});
function showHide(el){
// get the selector to find the target elements. its stored as data-.. attribute
var target = el.data("cqDialogCheckboxShowhideTarget");
// is checkbox checked?
var checked = el.prop('checked');
// get the selected value
// if checkbox is not checked, we set the value to empty string
var value = checked ? el.val() : '';
// make sure all unselected target elements are hidden.
$(target).not(".hide").addClass("hide");
// unhide the target element that contains the selected value as data-showhidetargetvalue attribute
$(target).filter("[data-showhidetargetvalue='" + value + "']").removeClass("hide");
}
})(document,Granite.$);

Control with bound property doesn't display model data in the UI

I'm migrating my app to new version of OpenUI5 (1.48) and have some problems with model bindings. I am using sap.ui.getCore().setModel(oModel, "myModel") for model declaration and when I'm trying to bind some controls to values from this model like this ...
<Text text="{local>/count}" />
... the value isn't displayed.
But if I get this model, set it to view in controller ...
var oModel = sap.ui.getCore().getModel("local");
this.getView().setModel(oModel);
<Text text="{/count}" />
... everything would work fine.
Maybe somebody faced a similar problem or has an idea what is wrong with my code?
You must be using a Component in your app. In that case, core models are not automatically propagated to the children of the ComponentContainer which is why your Text control doesn't know the model "local".
The reason why "{/count}" works is because you set the model explicitly on the view without any model name. If the model doesn't have a name, it's a default model and > has to be omitted in the binding path.
To learn more about where to set models, take a look at my answer to a similar question: https://stackoverflow.com/a/42251431/5846045
I think problem may be how you creating the JSON model!,
try this one.
Controller
sap.ui.define(["sap/ui/core/mvc/Controller",
"sap/ui/model/json/JSONModel",],
function(Controller,JSONModel) {
"use strict";
return Controller.extend("com.stackoverflow.testUI5", {
onInit:function(){
var oData = {
count:"1"
};
var oModel = new JSONModel(oData);
sap.ui.getCore().setModel(oModel , "local")
//this.getView().setModel(oModel ,"local");
}
});
});
XML View
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE xml>
<mvc:View controllerName="com.stackoverflow.testUI5"
xmlns:mvc="sap.ui.core.mvc"
xmlns:core="sap.ui.core" xmlns="sap.m" >
<Text text="{local>/count}"/>
</mvc:View>
this snippet will work.

Combobox in sap.ui.table.Table

I want to set values in a Combobox in the table: It does not show me the values ? Here is the code:
View:
<Column width="10rem">
<m:Label text="{i18n>Status}" />
<template>
<m:ComboBox items="{items>/Status}"
templateShareable="true">
<m:items>
<core:Item text="{Name}" />
</m:items>
</m:ComboBox>
</template>
</Column>
Controller: This is the parameterset.
success : function(oData, oResponse) {
// create JSON model
var oODataJSONModel = new sap.ui.model.json.JSONModel();
var child1 = [];
child1.push({Name:"S"});
child1.push({Name:"E"});
oData.Status = child1;
oODataJSONModel.setData(oData);
oView.setModel(oODataJSONModel, "items");
Thanks for helping!
You're missing alias for model in property binding of Item.
<core:Item text="{items>Name}" />
If you want to read the value of the combobox when it changes you can do the following. First in the XML, set the property selectionChange="nameOfYourFunction" in the combobox element. Whenever the user clicks on a different item, nameOfYourFunction() will execute. Here in this function you can check for the value.
nameOfYourFunction : function(){
//Do whatever you want to do here when user changes value of combo
this.getView().byId("combobox_id_here").getValue(); // returns text inside combobox
}
You might have to play around with the function and see when exactly it gets called. I have done a little with it and sometimes it gets called twice. I think once when the Combobox's text is a value in the list and then it gets called again when you leave focus of the combobox. Getting called twice probably won't affect your code though, depends on what you do in your function.