How to format a value from model before it is used as a control property? - sapui5

var oModel = new sap.ui.model.json.JSONModel();
var modelData = {
greet: "hello"
};
oModel.setData(modelData);
var oTextView = new sap.ui.commons.TextView({
text: "{/greet}" + "?" // "{/greet}" interpreted as ordinary string in this case
});
oTextView.setModel(oModel);
oTextView.placeAt("content");
To make the issue simple, my problem can be simplified as follows:
I would like to append a question mark to the text of a TextView. However, the leading part of the text is from the model. Indeed, in this simple case, I could have accessed the text from the model before it is combined with the question mark. After the target string is produced, I can assign it to the text property of TextView. However, what if the model gets changed else where? The code accessing the text property won't be guaranteed to be executed, so the text of TextView won't get updated?
Is there any way to solve this problem?

You can use complex binding syntax for this. Simply add this to your bootstrap:
data-sap-ui-xx-bindingSyntax="complex"
This enables you to combine model values with static text values like this:
var oTextView = new sap.ui.commons.TextView({
text: "{/greet} ?"
});
or even something like this:
var oTextView = new sap.ui.commons.TextView({
text: "{/lastName}, {/firstName}"
});
If your static text part depends on the model value you can add a formatter function, for example:
var oTextView = new sap.ui.commons.TextView({
text: {
path : "/greet", // no curly braces here!
formatter : function(greet) {
if(greet === "hello") {
return greet + "!";
} else if (greet === "how are you") {
return greet + "?";
} else {
return greet;
}
}
});

Related

VSCode custom language extention - Show CompletionItems for variable

I'm working on a custom language extension and I'm having issues with how to show functions for a variable.
I'm importing my language in the form of json, so i've created a typescript-file that i import into my extensions.ts:
export interface CustomIntellisense {
text: string;
help: string;
}
const data = [{
"text": "Void.String",
"help": "<h1>String String()</h1><p>Default constructor.<code>String something;</code></p>"
},
{
"text": "String.toInteger",
"help": "<h1>Integer toInteger()</h1><p>Converts a String to its numeric representation."
},
{
"text": "Void.Integer",
"help": "<h1>Integer Integer()</h1><p>Default constructor.</p>"
}];
export let json: CustomIntellisense[] = data;
My idea here is that the elements containing "Void" in text gets created as a variable, while the other element gets added as a method.
const provider1 = vscode.languages.registerCompletionItemProvider({ language: 'myLanguage', scheme: 'file' }, {
provideCompletionItems(document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken, context: vscode.CompletionContext) {
let items: vscode.CompletionItem[] = [];
let re = /\"/gi;
json.forEach(element => {
const item = new vscode.CompletionItem(element.text.split('.')[1]);
item.insertText = new vscode.SnippetString(element.help);
const markdownDocumentation = new vscode.MarkdownString();
markdownDocumentation.supportHtml = true;
markdownDocumentation.appendMarkdown(element.help);
item.documentation = markdownDocumentation;
if (element.text.includes('Void.')) { //If text includes Void this should be a variable
item.kind = vscode.CompletionItemKind.Variable;
}
else {
item.kind = vscode.CompletionItemKind.Method;
}
items.push(item);
});
return items;
}
});
The items gets added to the view, but I can't figure out how to 'filter' what is shown.
The official example on how to achieve this can be found here:
https://github.com/microsoft/vscode-extension-samples/blob/main/completions-sample/src/extension.ts
But this only explains how to filter based on the text/name, and i cant filter this specifically for each variableName i use.. If i somehow could detect what kind of Variable i'm working on I could possibly create a function that fetches if its a String/Int, then parse through my file and add methods in my 2nd CompletionItemProvider. But I havent found any good way of deciding the type of variable..
What i want is this:
If i click ctrl+space i want toInteger() to be the only thing that shows up, but instead it lists up everything all the time:
Anyone have a clue how to achieve this?

sap.m.table multi checkbox make it READ ONLY - On Condition + SAP UI5

This is my first post to Stack, appreciate the work you guys do, amazing.
I have a sap.m.table sap ui5 and i have 4 records
out of 4, 2 are selected by default, i want to disable the preselected once based on condition.
I have tried below code but its not working, any input please?
View
/results' }" **mode="MultiSelect"**
Controller logic
//--->disable the selected department checkboxes
var tbl = that.getView().byId('idImpactTable');
var header = tbl.$().find('thead');
var selectAllCb = header.find('.sapMCb');
selectAllCb.remove();
tbl.getItems().forEach(function(r) {
var obj = r.getBindingContext("impactModel").getObject();
var oStatus = obj.COMPLETED;
var cb = r.$().find('.sapMCb');
var oCb = sap.ui.getCore().byId(cb.attr('id'));
if (oStatus === "X") {
oCb.setSelected(true);
oCb.setEnabled(false);
} else {
oCb.setEnabled(false);
}
});
Multiselect Mode Table - Make selected check box read only
Last time I tried this I found it easiest to use the updateFinished event on the table, and then use an internal property of the column list item, like so:
onTableUpdateFinished: function (oEvent) {
oEvent.getSource().getItems().forEach(function (item) {
var data = item.getBindingContext().getObject();
item._oMultiSelectControl.setEnabled(!data.IsEnabled); //whatever your check is
});
}
You'll have to find a way to keep them disabled though when using the Select All checkbox at the top of the table. I ended up extending sap.m.Table to accomplish that, there might be easier ways...
My extension is like this
sap.ui.define([
"sap/m/Table"
], function(Control) {
return Control.extend("myapp.controls.MyTable", {
updateSelectAllCheckbox: function(oEvent) {
if (this._selectAllCheckBox && this.getMode() === "MultiSelect") {
var aItems = this.getItems();
var iSelectedItemCount = this.getSelectedItems().length;
var iSelectableItemCount = aItems.filter(function(oItem) {
//standard table does not check if the item is enabled
return oItem.getSelected() || oItem._oMultiSelectControl.getEnabled();
}).length;
// set state of the checkbox by comparing item length and selected item length
this._selectAllCheckBox.setSelected(aItems.length > 0 && iSelectedItemCount === iSelectableItemCount);
}
}
});
});
And just the standard renderer
sap.ui.define([
"sap/m/TableRenderer"
], function(Control) {
return Control.extend("myapp.controls.MyTableRenderer", {
});
});
I suppose I could have extended the ColumnListItem but that was more effort than I wanted to put into the table extension
I have managed to find the solution, please find sample code to achieve.
//--->disable the selected department checkboxes
var tbl = that.getView().byId("idImpactTable");
var header = tbl.$().find("thead");
var selectAllCb = header.find(".sapMCb");
selectAllCb.remove();
var aItems = that.byId("idImpactTable").getItems();
//---> Check individual item property value and select the item
aItems.forEach(function(oItem) {
debugger;
//---> If using OData Model items Binding, get the item object
var mObject = oItem.getBindingContext().getObject();
var sPath = oItem.getBindingContextPath();
var completed = oItem.oBindingContexts.impactModel.getProperty("COMPLETED");
//--->get the id of Multi Checkbox
var cb = oItem.$().find(".sapMCb");
var oCb = sap.ui.getCore().byId(cb.attr("id"));
if (completed === "X") {
oCb.setEditable(false);
oItem.setSelected(true);
oItem.getCells()[4].setEnabled(false);
} else {
oItem.setSelected(false);
}
});
Thank you,
Jacob.Kata
//--->disable the selected department checkboxes
var tbl = that.getView().byId('idImpactTable');
tbl.getItems().forEach(function(r) {
// this makes the trick --->
var oMultiSelCtrl = r.getMultiSelectControl();
oMultiSelCtrl.setDisplayOnly( true );
});

How to get the data of a view

I´m using SAPUI5, I have a MasterPage and a DetailPage, in the MasterPage I have a List and when I select de Item in the List the information is displayed in the DetailPage.
In the DetailPage I have a PositiveAction, When I press the PositiveAction I need to get the Data of the DetailPage but I don't know how to do this.
My code of the Item Press
onPoSelect : function(oEvent) {
var oListItem = oEvent.getParameter('listItem');
var oRouter = sap.ui.core.UIComponent.getRouterFor(this);
oRouter.navTo("DetailPanel", {
invoicePath: oListItem.getBindingContext("solped").getPath().substr(1)
});
},
My code in the DetailPanel
onInit: function (){
var oRouter = sap.ui.core.UIComponent.getRouterFor(this);
oRouter.getRoute("DetailPanel").attachPatternMatched(this._onObjectMatched, this);
},
_onObjectMatched: function (oEvent) {
this.getView().bindElement({
path: "/" + oEvent.getParameter("arguments").invoicePath,
model: "solped"
});
},
The line "oEvent.getParameter("arguments").invoicePath,"
returns this.
Invoices(CustomerName='Alfreds Futterkiste',Discount=0f,OrderID=10702,ProductID=3,ProductName='Aniseed Syrup',Quantity=6,Salesperson='Margaret Peacock',ShipperName='Speedy Express',UnitPrice=10.0000M)
I have the information but it is a String, How can I convert this String in an Object? Or, how else can I access the information in the view?
The image of the View
enter image description here
I assume you can already see the data of the detail in your Detail view.
You binded the data to the view by bindElement function and to retrieve them back in the code you are looking for "getBindingContext" function.
Create following function in your Detail controller:
// this must be connected to Button -> <Button press="onPositivePress">
onPositivePress: function(oEvent) {
var oBindingContext = this.getView().getBindingContext("solped");
// this is the path you can use to call odata service
var sPath = oBindingContext.getPath();
// this is data you are looking for
var oReqData = oBindingContext.getObject();
}
You can get all the properties as an object by passing the binding path as an argument to the getProperty function of the underlying Data model.
var oModel = this.getView().getModel("solped");
var oProps = oModel.getProperty(oListItem.getBindingContext("solped").getPath());
You can then access these properties as
oProps.CustomerName;
oProps.OrderID;
...
for converting string to object see below example.
var a = "how r u";
var b = [a];
you will get object of a in b.

sapui5 :- text not shown on ui5 in Dropdown Box

The values are loaded from the data source but on ui no text is shown.
var r0c1 = new sap.ui.commons.DropdownBox("r0c1");
var oItemTemplate1 = new sap.ui.core.ListItem();
property binding is done:
oItemTemplate1.bindProperty("text", "{ZtmDockid}");
bind the items:
r0c1.bindItems("/d/results", oItemTemplate1);
Data is properly coming, but on UI its not showing the text.
there are two ways to bind data to a control.
First way using bindProperty:
var oItemTemplate1 = new sap.ui.core.ListItem();
oItemTemplate1.bindProperty("text", "value");
(notice: usage of { })
or binding the values when creating the control:
var oItemTemplate1 = new sap.ui.core.ListItem({
text: "{value}"
});
(you need to use { } to indicate dynamic values)
Herrlock is correct, but I wanted to draw out the subtlety - explicit binding with the bind* functions requires no curly braces ... these are only needed for embedded, or implicit binding.
Here's your code with the braces removed from your bindProperty's second parameter, as a runnable snippet.
// Code from question
var r0c1 = new sap.ui.commons.DropdownBox("r0c1");
var oItemTemplate1 = new sap.ui.core.ListItem();
oItemTemplate1.bindProperty("text", "ZtmDockid");
r0c1.bindItems("/d/results", oItemTemplate1);
// Extra code
r0c1
.setModel(new sap.ui.model.json.JSONModel({
d : {
results : [
{ ZtmDockid : "1" },
{ ZtmDockid : "2" },
{ ZtmDockid : "3" }
]
}
}))
.placeAt('content');
<script src="https://openui5.hana.ondemand.com/resources/sap-ui-core.js"
data-sap-ui-libs="sap.m,sap.ui.commons"
data-sap-ui-theme="sap_bluecrystal"></script>
<div id="content"></div>

how to ask for new value before showing to the user?

I found this sample code where i can replace something automatically in the page
// If content-type is HTML, then remove all DIV tags
if (oSession.oResponse.headers.ExistsAndContains("Content-Type", "html")){
// Remove any compression or chunking
oSession.utilDecodeResponse();
var oBody = System.Text.Encoding.UTF8.GetString(oSession.responseBodyBytes);
// Replace all instances of the DIV tag with an empty string
var oRegEx = /<div[^>]*>(.*?)<\/div>/gi;
oBody = oBody.replace(oRegEx, "");
// Set the response body to the div-less string
oSession.utilSetResponseBody(oBody);
}
But how can i ask for the new value, instead of replacing it automatically?
See if this works for you
if (oSession.uriContains("/yoururl/here")) {
oSession.utilDecodeResponse();
var oBody = System.Text.Encoding.UTF8.GetString(oSession.responseBodyBytes);
var oRegEx = /this text will be replaced everywhere/gi;
var mydefaulttext = 'new text';
var mymsgbox = FiddlerScript.prompt('Lets change something', mydefaulttext);
oBody = oBody.replace(oRegEx, mymsgbox);
oSession.utilSetResponseBody(oBody);
}
OnBeforeResponse