How to make out of input field a hyperlink? - sapui5

As the title states, I would like to make out of an input a clickable hyperlink.
Code:
<Label text="Stackoverflow" />
<Input enabled="true" editable="false" name="Stackoverflow" value="Example" />
Issue: I want to display Example in the input as value, however, when clicking on the Example - to take you to stackoverflow.com.
Question: How to make it possible?

Without knowing what the use of the links are, generally, sap.m.InputBase controls can contain links within the value state message (Since 1.78).
sap.ui.getCore().attachInit(() => sap.ui.require([
"sap/ui/core/Fragment"
], Fragment => Fragment.load({
definition: `<Input xmlns="sap.m"
width="12rem"
valueState="Information"
placeholder="Input with links"
class="sapUiTinyMargin">
<formattedValueStateText>
<FormattedText htmlText="See %%0 and %%1.">
<controls>
<Link text="Link 1" press="alert('Link 1 clicked!')" />
<Link text="Link 2" press="alert('Link 2 clicked!')" />
</controls>
</FormattedText>
</formattedValueStateText>
</Input>`,
}).then(control => control.placeAt("content"))));
<script id="sap-ui-bootstrap"
src="https://openui5.hana.ondemand.com/resources/sap-ui-core.js"
data-sap-ui-libs="sap.ui.core, sap.m"
data-sap-ui-async="true"
data-sap-ui-theme="sap_fiori_3"
data-sap-ui-compatversion="edge"
data-sap-ui-excludejquerycompat="true"
data-sap-ui-xx-waitfortheme="init"
></script>
<body id="content" class="sapUiBody"></body>

Even if a link or button would be the better solution, here is my suggestion:
XML with custom attribute "url"
<Input enabled="true" editable="false" id="idInputStack" name="Stackoverflow" value="Example">
<customData>
<core:CustomData key="url" value="https://www.stackoverflow.com" writeToDom="true" />
</customData>
</Input>
Controller:
var oInput = this.getView().byId("idInputStack");
oInput.addEventDelegate({
onclick: function() {
document.location.href = oInput.data("url"); //get custom attribute url
}
})

First we would provide an id to the Input control so that we could refer to the same from the controller.
<Input enabled="true" editable="false" name="Stackoverflow" value="Example" id="myInputLinkId"/>
Now we could add the typical user click event to the Input field by attaching a Browser event to the same and place it in the onInit() hook method so that it is always accessible.
onInit: function () {
this.getView().byId("myInputLinkId").attachBrowserEvent('click',function(){ window.open("https://stackoverflow.com/");});
}

Related

Using a controller and and view together

I'm writing my first SAP app, and having gone through some of the tutorials, I understand that I need a controller for my view if I want it to do anything.
When I add the controllerName="./controller/login" (the controller's called 'login.controller.js'), it doesn't work, and I've tried variations of this.
The tutorials get me to copy code that uses the controller name, but they don't teach me anything about how to write the string for my own controller code.
How do I do this?
Controller code looks like this so far:
sap.ui.define([
"sap/ui/core/mvc/Controller"
], function(Controller) {
"use strict";
return Controller.extend("controller.Login", {
// controller logic goes here
});
});
and the view code looks like this:
<mvc:View
controllerName="controller.Login"
xmlns="sap.m"
xmlns:form="sap.ui.layout.form"
xmlns:mvc="sap.ui.core.mvc">
<Panel headerText="{/panelHeaderText}" class="sapUiResponsiveMargin" width="auto">
<form:SimpleForm editable="true" layout="ColumnLayout">
<Label text="User Name"/>
<Input value="{/firstName}" valueLiveUpdate="true" width="200px"/>
<Label text="Password"/>
<Input value="{/lastName}" valueLiveUpdate="true" width="200px"/>
<Button text="login" press=".onVisitHomePage"/>
</form:SimpleForm>
</Panel>
</mvc:View>
I'm going to add the .onVisitHomePage function to the controller but first I want to get this to work.
Like Julian Schmuckli already said you have to prefix the controller.login with your Namespace check you index.html where you initialize the sap-ui-core (see below).
<script src="resources/sap-ui-core.js" id="sap-ui-bootstrap"
data-sap-ui-theme="sap_bluecrystal" data-sap-ui-libs="sap.m"
data-sap-ui-bindingSyntax="complex" data-sap-ui-compatVersion="edge"
data-sap-ui-preload="async" data-sap-ui-async="true"
data-sap-ui-frameOptions="trusted" data-sap-ui-appCacheBuster="./"
data-sap-ui-resourceroots='{
"your.namespace": "./",
"sap.ui.demo.mock": "mockdata"
}'></script>
Here you have to take the string that is in place of the "your.namespace" and combine it with the controller.login to your.namespace.controller.login .
You have to do this in both the view and the controller file.

Control for displaying level of cost with currency signs

This might be an opinionated question, but I'd like to ask it because capabilities of UI5 are quite broad. I need to have these elements as
To which I am planning to introduce a custom font. Do you think it's a good solution or is there any better way to do that with some out of the box solutions?
What you're looking for is sap.m.RatingIndicator.
<RatingIndicator
editable="false"
maxValue="6"
value="4"
iconSelected="imageOrIconURI1"
iconUnselected="imageOrIconURI2"
/>
API reference
Samples
In your case, you'll need two images: one for the cash / currency symbol, and one greyed-out version of it. Both URIs should be assigned to iconSelected and iconUnselected accordingly.
Here is my attempt:
sap.ui.require([
"sap/ui/core/Core"
], Core => Core.attachInit(() => sap.ui.require([
"sap/ui/core/Fragment",
"sap/ui/model/json/JSONModel",
"sap/ui/core/theming/Parameters",
], async (Fragment, JSONModel, ThemeParameters) => {
"use strict";
const control = await Fragment.load({
definition: `<form:SimpleForm xmlns:form="sap.ui.layout.form" xmlns="sap.m">
<Label text="Cost A" />
<RatingIndicator
displayOnly="true"
editable="false"
maxValue="6"
value="4"
iconSelected="{myCurrency>/filled}"
iconUnselected="{myCurrency>/unfilled}"
/>
<Label text="Cost B" />
<RatingIndicator
displayOnly="true"
editable="false"
maxValue="6"
value="2"
iconSelected="{myCurrency>/filled}"
iconUnselected="{myCurrency>/unfilled}"
/>
</form:SimpleForm>`,
});
//==================================================================
//============= Sample rating indicator icons ======================
const currencyCode = "€";
// determine theme-dependent color values for font colors:
const colorFilled = ThemeParameters.get("sapUiContentForegroundTextColor").replace("#", "%23");
const colorUnfilled = ThemeParameters.get("sapUiContentImagePlaceholderBackground").replace("#", "%23");
const model = new JSONModel({ // assign the icon URIs, e.g. data-URI with SVG content:
filled: `data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg'
viewBox='0 0 14 14'>
<text x='50%' y='66%'
fill='${colorFilled}'
dominant-baseline='middle'
text-anchor='middle'>
${currencyCode}
</text>
</svg>`,
unfilled: `data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14 14'>
<text x='50%' y='66%'
fill='${colorUnfilled}'
dominant-baseline='middle'
text-anchor='middle'>
${currencyCode}
</text>
</svg>`,
});
control.setModel(model, "myCurrency").placeAt("content");
})));
<script id="sap-ui-bootstrap"
src="https://openui5.hana.ondemand.com/resources/sap-ui-core.js"
data-sap-ui-libs="sap.ui.core, sap.m, sap.ui.layout"
data-sap-ui-async="true"
data-sap-ui-theme="sap_fiori_3"
data-sap-ui-compatversion="edge"
data-sap-ui-xx-waitfortheme="init"
></script>
<body id="content" class="sapUiBody sapUiSizeCompact"></body>
Since I put a plain text character to the SVG, the "image" is zoomable without losing quality and the color can be also made theme-dependent as shown above. But of course, you can also just use two raster images instead.
Either way, I believe the RatingIndicator is a good candidate which could be used instead of creating and maintaining a custom control or custom font.

Deselect Radiobuttons when leaving the view via cancel button

I have a table(sap.m.table) with radiobutton control in the first column.
The table shows different "prices" from which the user should be able to choose only one. My problem is, when i use the cancel button it should delete all selections made (in dropdowns, datefilter, etc.). It works for every control except radiobutton.
<ColumnListItem> <cells>
<RadioButton id="radiobutton" groupName="tablebuttons" select="onSelect"/>.....
When i leave the view with the cancel button and then open it again in the same session, the previous selected radiobutton is still selected.
I cant find any method to set it to unselected. When i use this.getView().byId("radiobutton").getSelected()
it always gives back "false".
Is it because there is one button for each table row and i only select (the first?) one? If so, how can i search all button for the selected one and deselect it?
You must have added id="radiobutton" to the template list item which is used for aggregation binding. That is why calling byId("radiobutton") does not return any rendered radio button but the template instance. If you check the IDs of the radio buttons from the HTML document, you'll notice that they all contain the generated prefix __clone0, __clone1, etc.
I can't find any method to set it to unselected.
To deselect a radio button, use:
In case of RadioButton: .setSelected(false)
In case of RadioButtonGroup: .setSelectedIndex(-1)
But you might not even need any sap.m.RadioButton to add manually to the table. Since sap.m.Table extends from sap.m.ListBase, it can have a radio button in each list item via mode="SingleSelectLeft". Here is a demo:
sap.ui.getCore().attachInit(() => sap.ui.require([
"sap/ui/model/json/JSONModel"
], JSONModel => sap.ui.xmlview({
async: true,
viewContent: `<mvc:View
xmlns:mvc="sap.ui.core.mvc"
xmlns="sap.m"
controllerName="MyController"
>
<Table
mode="SingleSelectLeft"
selectionChange=".onSelectionChange"
includeItemInSelection="true"
items="{prices>/}">
<columns>
<Column>
<Text text="Price"/>
</Column>
<Column>
<Text text="Foo"/>
</Column>
</columns>
<items>
<ColumnListItem selected="{prices>selected}" >
<ObjectNumber number="{prices>price}" />
<Text text="bar" />
</ColumnListItem>
</items>
</Table>
<Button
class="sapUiTinyMargin"
text="Deselect"
type="Emphasized"
press=".onResetPress"
/>
</mvc:View>`,
controller: sap.ui.controller("MyController", {
onInit: function() {
const model = new JSONModel(this.createModelData());
this.getView().setModel(model, "prices");
},
onResetPress: function() {
const model = this.getView().getModel("prices");
model.setProperty("/", this.createModelData());
},
createModelData: () => [{
price: 111.01,
}, {
price: 222.0245,
}, {
price: 333,
}],
}),
}).loaded().then(view => view.placeAt("content"))));
<script src="https://openui5.hana.ondemand.com/resources/sap-ui-core.js" id="sap-ui-bootstrap"
data-sap-ui-libs="sap.m"
data-sap-ui-preload="async"
data-sap-ui-theme="sap_belize"
data-sap-ui-compatVersion="edge"
data-sap-ui-xx-waitForTheme="true"
></script><body id="content" class="sapUiBody sapUiSizeCompact"></body>
IMO, you should use a model to set/reset values and not called the setter function of control. here is an example of using MVC
http://jsbin.com/zijajas/edit?html,js,output
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta charset="UTF-8">
<title>MVC</title>
<script id="sap-ui-bootstrap" type="text/javascript"
src="https://sapui5.hana.ondemand.com/resources/sap-ui-core.js"
data-sap-ui-theme="sap_bluecrystal"
data-sap-ui-libs="sap.m,sap.ui.table"
data-sap-ui-xx-bindingSyntax="complex">
</script>
<script id="oView" type="sapui5/xmlview">
<mvc:View height="100%" controllerName="myView.Template"
xmlns="sap.m"
xmlns:core="sap.ui.core"
xmlns:mvc="sap.ui.core.mvc"
xmlns:table="sap.ui.table">
<table:Table id="Table1" rows="{/}"
selectionMode="None">
<table:title>
<Button icon="sap-icon://reset" press="reset" />
</table:title>
<table:columns>
<table:Column>
<Label text="Employee name"/>
<table:template>
<Text text="{name}" ></Text>
</table:template>
</table:Column>
<table:Column>
<Label text="Company"/>
<table:template>
<Text text="{company}"></Text>
</table:template>
</table:Column>
<table:Column>
<Label text="Radio"/>
<table:template>
<RadioButtonGroup selectedIndex="{radio}">
<RadioButton text="no" />
<RadioButton text="yes" />
</RadioButtonGroup>
</table:template>
</table:Column>
<table:Column>
<Label text="Bonus"/>
<table:template>
<Input value="{bonus}" />
</table:template>
</table:Column>
</table:columns>
</table:Table>
</mvc:View>
</script>
</head>
<body class="sapUiBody sapUiSizeCompact" role="application">
<div id="content"></div>
</body>
</html>
controller
sap.ui.define([
'jquery.sap.global',
'sap/ui/core/mvc/Controller',
'sap/ui/model/json/JSONModel'
], function(jQuery, Controller, JSONModel) {
"use strict";
var oController = Controller.extend("myView.Template", {
onInit: function(oEvent) {
this.getView().setModel(new JSONModel([{
name : "John",
company: "apple inc",
radio: 0,
bonus: "0"
}, {
name : "Mary",
company: "abc inc",
radio: 0,
bonus: "0"
},
]));
},
reset: function() {
var oModel = this.getView().getModel();
oModel.getProperty('/').forEach(function(item) {
item.radio = 0;
item.bonus = 0;
});
oModel.refresh();
}
});
return oController;
});
var oView = sap.ui.xmlview({
viewContent: jQuery('#oView').html()
});
oView.placeAt('content');

How to extend "sap.m.Dialog" to add custom content to Dialog footer?

I am trying to make a custom dialog to show some text and link in the footer along with buttons. I don't know how to change the existing rendering for this, so I wrote a simple renderer to check the behavior. This is my code:
sap.m.Dialog.extend("EnhancedDialog",{
metadata:{
properties:{
footerLabelText:{type:"string",defaultValue:null},
footerLinkText:{type:"string",defaultValue:null},
footerLinkHref:{type:"string",defaultValue:null}
},
aggregations:{
_label:{type:"sap.m.Label",multiple:false,visibility:"hidden"},
_link:{type:"sap.m.Link",multiple:false,visibility:"hidden"}
},
events:{}
},
init:function(){
this.getAggregation("_label", new sap.m.Label({text:"Check"}));
this.getAggregation("_link",new sap.m.Link({text:"Link"}));
},
setFooterLabelText:function(oLabelText){
this.setProperty("footerLabelText",oLabelText,true);
this.getAggregation("_label").setText(oLabelText);
},
setFooterLinkText:function(oLinkText){
this.setProperty("footerLinkText",oLinkText,true);
this.getAggregation("_link").setText(oLinkText);
},
setFooterLinkHref:function(oLinkHref){
this.setProperty("footerLinkHref",oLinkHref,true);
this.getAggregation("_link").setHref(oLinkHref);
},
renderer:{
render:function(oRM,oControl){
oRM.write("<div");
oRM.writeControlData(oControl);
oRM.writeClasses();
oRM.write(">");
oRM.renderControl(oControl.getAggregation("_label"));
oRM.renderControl(oControl.getAggregation("_link"));
oRM.write("</div");
}
}
});
var enhancedDialog=new EnhancedDialog();
var btn=new sap.m.Button({
text:"Click Here!",
press: function(){
enhancedDialog.open();
}
});
But I am getting the error
Dialog.js:6 Uncaught TypeError: Cannot read property 'setInitialFocusId' of undefined
when I am clicking the button.
Can someone point out what I am doing wrong?
And how to change the existing renderer behavior to show text in the footer?
This is what I want to make:
The error you are seeing is because you have overwritten the init() method and not called the overwritten init() of Dialog. So the internal popup and other stuff does not get initialized. You have to call the base.init() this way:
init:function(){
sap.m.Dialog.prototype.init.apply(this,arguments);
this.getAggregation("_label", new sap.m.Label({text:"Check"}));
this.getAggregation("_link",new sap.m.Link({text:"Link"}));
},
However you will need to copy most of the DialogRenderers code to get a fully functional dialog.
Alternatively you could use the unmodified DialogRender and overwrite the Dialog._createToolbarButtons() method to add your Label and Link to the beginning:
_createToolbarButtons:function () {
Dialog.prototype._createToolbarButtons.apply(this,arguments);
var toolbar = this._getToolbar();
var toolbarContent = toolbar.getContent();
toolbar.removeAllContent();
toolbar.addContent(this.getAggregation("_label"));
toolbar.addContent(this.getAggregation("_link"));
// insertContent is not implemented correctly...
toolbarContent.forEach(function(control){toolbar.addContent(control)});
},
renderer:DialogRenderer
Full example on Plunker.
[...] show some text and link in the footer along with buttons.
Having a customizable Dialog footer is now supported since UI5 1.110. Simply define sap.m.Toolbar in the new <footer> aggregation of your sap.m.Dialog. For example:
<Dialog xmlns="sap.m" title="Title" initialFocus="okButton">
<!-- ... -->
<footer> <!-- Since UI5 1.110: -->
<Toolbar>
<Text text="Some text!" />
<ToolbarSpacer />
<Button id="okButton" text="OK" type="Emphasized" />
<Button text="Cancel" />
</Toolbar>
</footer>
</Dialog>
Sample demo:
globalThis.onUI5Init = () => sap.ui.require([
"sap/ui/core/mvc/XMLView",
], async (XMLView) => {
"use strict";
const control = await XMLView.create({
definition: `<mvc:View xmlns:mvc="sap.ui.core.mvc"
xmlns="sap.m"
displayBlock="true"
height="100%"
>
<App autoFocus="false">
<dependents>
<Dialog id="myDialog"
class="sapUiResponsiveContentPadding sapUiResponsivePadding--header sapUiResponsivePadding--content sapUiResponsivePadding--footer"
initialFocus="okButton"
title="Title"
draggable="true"
resizable="true"
>
<Text text="Content ..." />
<footer>
<Toolbar>
<Text text="Some text in the footer!" />
<ToolbarSpacer />
<Button id="okButton" text="OK" type="Emphasized" />
<Button text="Cancel" />
</Toolbar>
</footer>
</Dialog>
</dependents>
</App>
</mvc:View>`,
afterRendering: function () {
this.byId("myDialog").open();
}
});
control.placeAt("content");
})
<script id="sap-ui-bootstrap"
src="https://sdk.openui5.org/nightly/resources/sap-ui-core.js"
data-sap-ui-libs="sap.ui.core,sap.m,sap.ui.unified,sap.ui.layout"
data-sap-ui-async="true"
data-sap-ui-oninit="onUI5Init"
data-sap-ui-theme="sap_horizon"
data-sap-ui-compatversion="edge"
data-sap-ui-excludejquerycompat="true"
data-sap-ui-xx-waitfortheme="init"
></script>
<body id="content" class="sapUiBody sapUiSizeCompact"></body>

How can I put icon and text in select items

I have an sap.m.Select control for a list of countries and I need to put flag near everyone. How can I do it? In XML, if it's possible.
Here is my XML code:
<m:Label text="{i18n>COUNTRY}" />
<m:Select width="100px"
fieldWidth="60%"
class="xcuiInputNoMargin"
enabled="{Edit>/EditOn}"
items="{countryList>/}"
>
<core:Item
key="{countryList>Country}"
text="{countryList>Country} - {countryList>Name}"
/>
</m:Select>
The sap.m.Select Object is restricted to display text (or Like #Jasper_07 said) icon only.
I think that the best solution for your problem is to use another object instead of your select. You can use Select Dialog and put inside whatever you want, like listItem with image.
This is an example:
<SelectDialog
noDataText="No Products Found"
title="Select Product"
search="handleSearch"
confirm="handleClose"
close="handleClose"
items="{
path: '/ProductCollection'
}" >
<StandardListItem
title="{Name}"
description="{ProductId}"
icon="{ProductPicUrl}"
iconDensityAware="false"
iconInset="false"
type="Active" />
</SelectDialog>
see link bellow
As of UI5 version 1.62, the following controls support displaying the icon on the left side.
sap.m.Select
sap.m.SelectList
And other controls based on the above mentioned ones, such as sap.m.ComboBox.
Here is an example:
sap.ui.getCore().attachInit(() => sap.ui.require([
"sap/ui/core/mvc/XMLView",
], XMLView => XMLView.create({
definition: `<mvc:View xmlns:mvc="sap.ui.core.mvc" height="100%">
<Select xmlns="sap.m" xmlns:core="sap.ui.core" class="sapUiTinyMargin">
<core:ListItem text="Paper plane" icon="sap-icon://paper-plane" />
<core:ListItem text="Stop Watch" icon="sap-icon://fob-watch" />
<core:ListItem text="Umbrella" icon="sap-icon://umbrella" />
</Select>
</mvc:View>`
}).then(view => view.placeAt("content"))));
<script id="sap-ui-bootstrap"
src="https://openui5nightly.hana.ondemand.com/resources/sap-ui-core.js"
data-sap-ui-libs="sap.ui.core, sap.m"
data-sap-ui-preload="async"
data-sap-ui-async="true"
data-sap-ui-theme="sap_belize"
data-sap-ui-compatversion="edge"
data-sap-ui-xx-waitfortheme="true"
data-sap-ui-xx-xml-processing="sequential"
></script>
<body id="content" class="sapUiBody sapUiSizeCompact"></body>
Keep in mind to use sap.ui.ListItem as an aggregation child in this case, instead of sap.ui.core.Item.
Limitation
Currently, the icon property only allows resource paths from "sap-icon://*". I.e. images, that are not icons such as country flags, are not possible. A possible workaround would be to make use of emoji flags as additionalText.
Otherwise, I'd recommend to look for alternative controls as shmoolki suggested.
from the documentation of sap.m.Select
The URI to the icon that will be displayed only when using the
IconOnly type
seems limiting, but try
<m:Select
type="sap.m.SelectType.IconOnly"
icon="sap-icon://cart">
</m:Select>