Access a property and change its value - sapui5

I am trying to get an access and change localModel>PROPERTY_VALUE in my controller. This was implemented before, not by me. So I am stuck here. I know, there is setProperty() that I could use, but still don't know how.
<xx:Repeater items="{
path: 'localModel>/reportData/',
filters: {
path: 'TYPE',
operator: 'EQ',
value1: 'CONCLUSION'
},
templateShareable: false
}">
<TextArea value="{localModel>PROPERTY_VALUE}" rows="8" width="100%"/>
</xx:Repeater>
controller.js
ReportService.getReportData(oDataModel, caseUuid).then(function (data) {
that.localModel.setProperty('/reportData/', data);
});
const interpretationTextArea = this.localModel.getProperty('/reportData').find(it => it.PROPERTY_NAME === 'CONCLUSION');
if (interpretationTextArea) {
interpretationTextArea.PROPERTY_VALUE = 'Bla' + interpretationTextArea.PROPERTY_VALUE;
}
Here is how data looks like inside:

Related

Adding a SimplePlanningCalendar to a UI5 app fails with `getKey` error

When I add a SimplePlanningCalendar to my app, I got the following Error.
I added the calendar with a minimal configuration to my app.
<IconTabBar xmlns="sap.m"
id="idCategoryMenu"
selectedKey="Home"
headerMode="Inline"
stretchContentHeight="true"
applyContentPadding="false"
select=".onSelectCategory"
items="{
path: 'backend>/CategorySet',
parameters: {
expand: 'Reports'
},
sorter: {
path: 'Sort'
},
templateShareable: true
}">
<items>
<IconTabFilter id="myIconTabFilter" key="{backend>Uuid}" text="{backend>Name}">
<!-- ... -->
<SinglePlanningCalendar>
<appointments>
<unified:CalendarAppointment xmlns:unified="sap.ui.unified"
title="{title}"
startDate="{startDate}"
endDate="{endDate}"
/>
</appointments>
</SinglePlanningCalendar>
<!-- ... -->
</IconTabFilter>
</items>
</IconTabBar>
When I debug the app, I come to the following line inside the SinglePlanningCalendar.js where a key from the given vView parameter is requested, but the parameter only holds a string.
Anyone else had this problem before and knows why or how to solve this?
The problem is caused by the control implementation itself in the current version (1.71.21) I use for my development.
The fix in the commit 45696fe is available as of UI5 1.75.x.
Since I cannot change my version, I implemented the given solution in my package:
{ // Controller
onInit: function () {
// ...
this.calendarTemporaryFix(); // Not needed since UI5 1.75
},
calendarTemporaryFix: function () {
// SinglePlanningCalendar required from "sap/m/SinglePlanningCalendar"
const fnSetSelectedView = SinglePlanningCalendar.prototype.setSelectedView;
SinglePlanningCalendar.prototype.setSelectedView = function (vView) {
if (typeof vView === "string") {
vView = sap.ui.getCore().byId(vView);
}
return fnSetSelectedView.call(this, vView);
};
},
// ...
}

Formatter function not working properly inside Input Control

I need to highlight a few of the table's cell border colors on the basis of a condition and pre-fill it with some negative value. Then I need to SAVE/POST this value to proceed further.
View.xml
<t:Column width="100px">
<Label text="ActualQty"/>
<t:template>
<Input id="idInput" value="{ parts: [ {path: 'viewData>ACT_QTY'}, {path: 'viewData>MTART'} ], formatter: '._formatter.defaultInput' }">
<customData>
<core:CustomData key="colorclass" value="{path: 'viewData>MTART', formatter: '._formatter.formatCell'}" writeToDom="true"/>
</customData>
</Input>
</t:template>
</t:Column>
Formatter.js
formatCell: function (iValue) {
try {
iValue.toString();
} catch (err) {
iValue = "foo";
}
return iValue.toString();
},
defaultInput: function (iValue, iValue1) {
if (iValue !== 0 && iValue1 === "HALB") {
iValue = "-1";
return iValue;
} else {
return iValue;
}
}
style.css
div[data-colorclass="HALB"] {
border: 4px solid #fdf6b1 !important;
}
Highlighting and the default value is appearing. But inside the controller, the input value is not coming.
If I remove parts and pass single input param to formatter function, it's working. But I need both the values to built my logic.
Update
Now I am using Composite Binding to make the binding as Two-way.
View.xml
<Input id="idInput" value="{ parts: [ {path: 'viewData>ACT_QTY'}, {path: 'viewData>MTART'} ], type: '._Compound', formatter: '._formatter.defaultInput' }">
Compound.js
sap.ui.define([
"sap/ui/model/CompositeType",
"dismantling/bom/integration/model/type/Compound"
], CompositeType => CompositeType.extend('Compound', {
constructor: function () {
CompositeType.apply(this, arguments);
this.bParseWithValues = true; // make 'parts' available in parseValue
},
formatValue: iValue => iValue,
parseValue: bValue => bValue,
validateValue: vValue => { /*validate...*/ },
}));
In the controller file, I am passing Compound type as _Compound. I am not getting any errors in the console.
Still, I am not able to get the formatter passed value inside the controller.
Your formatter is correct. Make sure sure that the values are actually accessible under your binding path and that the formatter is accessible to the view. If both these things are ensured, your function will work just fine.

Bootstrap-vue: Auto-select first hardcoded <option> in <b-form-select>

I'm using b-form-select with server-side generated option tags:
<b-form-select :state="errors.has('type') ? false : null"
v-model="type"
v-validate="'required'"
name="type"
plain>
<option value="note" >Note</option>
<option value="reminder" >Reminder</option>
</b-form-select>
When no data is set for this field I want to auto-select the first option in the list.
Is this possible? I have not found how to access the component's options from within my Vue instance.
your v-model should have the value of the first option.
example
<template>
<div>
<b-form-select v-model="selected" :options="options" />
<div class="mt-3">Selected: <strong>{{ selected }}</strong></div>
</div>
</template>
<script>
export default {
data() {
return {
selected: 'a',
options: [
{ value: null, text: 'Please select an option' },
{ value: 'a', text: 'This is First option' },
{ value: 'b', text: 'Selected Option' },
{ value: { C: '3PO' }, text: 'This is an option with object value' },
{ value: 'd', text: 'This one is disabled', disabled: true }
]
}
}
}
</script>
You can trigger this.selected=${firstOptionValue} when no data is set.
what if we don't know what the first option is. The list is generated?
if you have dynamic data, something like this will work.
<template>
<div>
<b-form-select v-model="selected" :options="options" />
<div class="mt-3">Selected: <strong>{{ selected }}</strong></div>
</div>
</template>
<script>
export default {
data() {
return {
selected: [],
options: [],
};
},
mounted: function() {
this.getOptions();
},
methods: {
getOptions() {
//Your logic goes here for data fetch from API
const options = res.data;
this.options = res.data;
this.selected = options[0].fieldName; // Assigns first index of Options to model
return options;
},
},
};
</script>
If your options are stored in a property which is loaded dynamically:
computed property
async computed (using AsyncComputed plugin)
through props, which may change
Then you can #Watch the property to set the first option.
That way the behavior of selecting the first item is separated from data-loading and your code is more understandable.
Example using Typescript and #AsyncComputed
export default class PersonComponent extends Vue {
selectedPersonId: string = undefined;
// ...
// Example method that loads persons data from API
#AsyncComputed()
async persons(): Promise<Person[]> {
return await apiClient.persons.getAll();
}
// Computed property that transforms api data to option list
get personSelectOptions() {
const persons = this.persons as Person[];
return persons.map((person) => ({
text: person.name,
value: person.id
}));
}
// Select the first person in the options list whenever the options change
#Watch('personSelectOptions')
automaticallySelectFirstPerson(persons: {value: string}[]) {
this.selectedPersonId = persons[0].value;
}
}

Set the aggregation text of fragments from controller

I have a xml-fragment. I set items as "{path: '/idFamiglia' }"
<core:FragmentDefinition
xmlns="sap.m"
xmlns:core="sap.ui.core">
<SelectDialog
id="idSelectDialog"
noDataText="Nessun dato"
title="Suggerimento"
search="handleLocalSearch"
liveChange="handleLocalSearch"
confirm="handleClose"
close="handleClose"
items="{
path: '/idFamiglia'
}">
<StandardListItem
title="{title}"
description="{description}"
icon=""
iconDensityAware="false"
iconInset="false"
type="Active" />
</SelectDialog>
</core:FragmentDefinition>
From the controller I want set this string. I try in this methods:
handleValueLocalHelp : function(oEvent) {
this.inputId = oEvent.oSource.sId;
if (!this._oDialog) {
this._oDialog = sap.ui.xmlfragment("ui5bp.view.fragment.HintLocalDialog",this);
}
//1
sap.ui.getCore().byId("idSelectDialog").setAggregation("items", "{path: '/idFamiglia'}");
//2
this._oDialog.bindElement("/idFamiglia");
//3
sap.ui.getCore().byId("idSelectDialog").bindElement("/idFamiglia");
this._oDialog.setModel(this.getView().getModel("hint"));
// toggle compact style
jQuery.sap.syncStyleClass("sapUiSizeCompact", this.getView(), this._oDialog);
this._oDialog.open();
},
I have some errors..
Uncaught Error: Aggregation 'items' of Element sap.m.List#idSelectDialog-list used with wrong cardinality (declared as 0..n) if I try the forst mode
If I try the second mode it not change the string
the same behavior
How can I modify the aggregation string (items for example) from controller?
Since the control you are using (SelectDialog), the "item" aggregation can only be used with sap.m.ListItemBase[] whereas I can see you are binding with '/idFamiglia'. This is not a property binding, it is can aggregation binding.
var oSelectDialog = new sap.m.SelectDialog({
multiSelect : true,
title : "Title",
items: {
path: "/",
template: new sap.m.StandardListItem({
title: "{text}",
description: "{key}"
//selected: "{JSON>selected}"
})
},
rememberSelections : true,
});
I try a solution to set a default fragment by XML-view and personalize it from controller:
handleValueLocalHelp : function(oEvent) {
this.inputId = oEvent.oSource.sId;
if (!this._oDialog) {
this._oDialog = sap.ui.xmlfragment("ui5bp.view.fragment.HintLocalDialog",this);
this._oDialog._dialog.mAggregations.content[1].mBindingInfos.items.path="/idFamiglia";
}

kendo ui mvvm: dynamically update multiselect datasource inside View Model' s change event

I have a View with two multiselect widgets whose values (region_edu_admin, edu_admin) and datasources (region_edu_admins_ds, edu_admins_ds) are binded (through data-bind) to a ViewModel. Inside region_edu_admin's change event (regionEduAdminChanged) i am trying to reload edu_admin's widget datasource, that is edu_admins_ds, by using the set method. Though i do get inside newEduAdminsDS(), the datasource does not get reloaded. Any ideas on what i' m missing here would be much appreciated! You can see the code below:
/* View Model */
var LabsSearchVM = kendo.observable({
region_edu_admins_ds: newRegionEduAdminsDS(),
edu_admins_ds: newEduAdminsDS(),
region_edu_admin: "",
edu_admin: "",
regionEduAdminChanged: function(e) {
this.set("edu_admins_ds", newEduAdminsDS());
}
});
/* View */
<label for="region_edu_admin">Περιφερειακή Διεύθυνση Εκπαίδευσης</label>
<select id="sl_region_edu_admin"
name="region_edu_admin"
data-role="multiselect"
data-auto-bind="false"
data-value-primitive="true"
data-text-field="name"
data-value-field="name"
data-bind="source: region_edu_admins_ds, value: region_edu_admin, events: {change : regionEduAdminChanged }"
data-filter="contains"
multiple="multiple">
</select>
<label for="edu_admin">Διεύθυνση Εκπαίδευσης</label>
<select id="sl_edu_admin"
name="edu_admin"
data-role="multiselect"
data-auto-bind="false"
data-text-field="name"
data-value-field="name"
data-bind="source: edu_admins_ds, value: edu_admin"
data-filter="contains"
multiple="multiple">
</select>
/* newEduAdminsDS() function */
function newEduAdminsDS() {
var edu_admins_ds = new kendo.data.DataSource({
transport: {
read: {
url: "api/edu_admins",
type: "GET",
dataType: "json"
}
},
schema: {
data: "data",
model: {
id: "edu_admin_id",
fields: {
edu_admin_id: { editable: false },
name: { editable: false },
region_edu_admin_id: { editable: false },
region_edu_admin: { editable: false }
}
}
}
});
return edu_admins_ds;
}
You do not need to re-create the DataSource. All you need to do is tell it to read() again to reload the data. Change the regionEduAdminChanged function in your observable to this:
regionEduAdminChanged: function(e) {
this.edu_admins_ds.read();
}